Libinfo-517.200.9.tar.gz
[apple/libinfo.git] / lookup.subproj / thread_data.c
1 /*
2 * Copyright (c) 2008-2018 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include "libinfo_common.h"
25
26 #include <thread_data.h>
27 #include <pthread.h>
28 #include <string.h>
29 #include <stdlib.h>
30
31 static pthread_key_t _info_key = 0;
32 static int _info_key_ok = 0;
33 static pthread_once_t _info_key_initialized = PTHREAD_ONCE_INIT;
34
35 struct _li_data_s
36 {
37 uint32_t icount;
38 uint32_t *ikey;
39 void **idata;
40 };
41
42 typedef struct
43 {
44 si_item_t *thread_item;
45 si_list_t *thread_list;
46 } li_thread_data_t;
47
48 static void
49 _LI_thread_info_free(void *x)
50 {
51 li_thread_data_t *tdata;
52
53 if (x == NULL) return;
54
55 tdata = (li_thread_data_t *)x;
56 si_item_release(tdata->thread_item);
57 si_list_release(tdata->thread_list);
58
59 free(tdata);
60 }
61
62 static void
63 _LI_data_free(void *x)
64 {
65 struct _li_data_s *t;
66 int i;
67
68 if (x == NULL) return;
69
70 t = (struct _li_data_s *)x;
71
72 for (i = 0; i < t->icount; i++)
73 {
74 _LI_thread_info_free(t->idata[i]);
75 t->idata[i] = NULL;
76 }
77
78 if (t->ikey != NULL) free(t->ikey);
79 t->ikey = NULL;
80
81 if (t->idata != NULL) free(t->idata);
82 t->idata = NULL;
83
84 free(t);
85 }
86
87 static void
88 _LI_data_init()
89 {
90 /* _info_key_ok is set to 1 if pthread_key_create succeeded */
91 if (pthread_key_create(&_info_key, _LI_data_free) == 0) _info_key_ok = 1;
92 return;
93 }
94
95 static struct _li_data_s *
96 _LI_data_get()
97 {
98 struct _li_data_s *libinfo_data;
99
100 /* only one thread should create the _info_key */
101 pthread_once(&_info_key_initialized, _LI_data_init);
102
103 /* no thread-specific data if pthread_key_create failed */
104 if (_info_key_ok == 0) return NULL;
105
106 /* Check if this thread already created libinfo_data */
107 libinfo_data = pthread_getspecific(_info_key);
108 if (libinfo_data != NULL) return libinfo_data;
109
110 libinfo_data = (struct _li_data_s *)calloc(1, sizeof(struct _li_data_s));
111 if (libinfo_data == NULL) return NULL;
112
113 pthread_setspecific(_info_key, libinfo_data);
114 return libinfo_data;
115 }
116
117 static li_thread_data_t *
118 LI_get_thread_info(uint32_t key)
119 {
120 struct _li_data_s *libinfo_data;
121 li_thread_data_t *tdata;
122 uint32_t i, n;
123
124 libinfo_data = _LI_data_get();
125 if (libinfo_data == NULL) return NULL;
126
127 for (i = 0; i < libinfo_data->icount; i++)
128 {
129 if (libinfo_data->ikey[i] == key) return libinfo_data->idata[i];
130 }
131
132 i = libinfo_data->icount;
133 n = i + 1;
134
135 if (i == 0)
136 {
137 libinfo_data->ikey = (uint32_t *)malloc(sizeof(uint32_t));
138 libinfo_data->idata = (void **)malloc(sizeof(void *));
139 }
140 else
141 {
142 libinfo_data->ikey = (uint32_t *)reallocf(libinfo_data->ikey, n * sizeof(uint32_t));
143 libinfo_data->idata = (void **)reallocf(libinfo_data->idata, n * sizeof(void *));
144 }
145
146 if ((libinfo_data->ikey == NULL) || (libinfo_data->idata == NULL))
147 {
148 if (libinfo_data->ikey != NULL) free(libinfo_data->ikey);
149 libinfo_data->ikey = NULL;
150
151 if (libinfo_data->idata != NULL) free(libinfo_data->idata);
152 libinfo_data->idata = NULL;
153
154 return NULL;
155 }
156
157 tdata = (li_thread_data_t *)calloc(1, sizeof(li_thread_data_t));
158 if (tdata == NULL) return NULL;
159
160 libinfo_data->ikey[i] = key;
161 libinfo_data->idata[i] = tdata;
162 libinfo_data->icount++;
163
164 return tdata;
165 }
166
167 LIBINFO_EXPORT
168 si_item_t *
169 LI_get_thread_item(uint32_t key)
170 {
171 li_thread_data_t *tdata;
172
173 tdata = LI_get_thread_info(key);
174 if (tdata == NULL) return NULL;
175
176 return tdata->thread_item;
177 }
178
179 LIBINFO_EXPORT
180 si_list_t *
181 LI_get_thread_list(uint32_t key)
182 {
183 li_thread_data_t *tdata;
184
185 tdata = LI_get_thread_info(key);
186 if (tdata == NULL) return NULL;
187
188 return tdata->thread_list;
189 }
190
191 LIBINFO_EXPORT
192 void
193 LI_set_thread_item(uint32_t key, si_item_t *item)
194 {
195 li_thread_data_t *tdata;
196
197 tdata = LI_get_thread_info(key);
198 if (tdata == NULL) return;
199
200 si_item_release(tdata->thread_item);
201 tdata->thread_item = item;
202 }
203
204 LIBINFO_EXPORT
205 void
206 LI_set_thread_list(uint32_t key, si_list_t *list)
207 {
208 li_thread_data_t *tdata;
209
210 tdata = LI_get_thread_info(key);
211 if (tdata == NULL) return;
212
213 si_list_release(tdata->thread_list);
214
215 si_list_reset(list);
216 tdata->thread_list = list;
217 }