1/*
2 * Copyright (c) 2008 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 <thread_data.h>
25#include <pthread.h>
26#include <string.h>
27#include <stdlib.h>
28
29static pthread_key_t _info_key = 0;
30static int _info_key_ok = 0;
31static pthread_once_t _info_key_initialized = PTHREAD_ONCE_INIT;
32
33struct _li_data_s
34{
35	uint32_t icount;
36	uint32_t *ikey;
37	void **idata;
38};
39
40typedef struct
41{
42	si_item_t *thread_item;
43	si_list_t *thread_list;
44} li_thread_data_t;
45
46static void
47_LI_thread_info_free(void *x)
48{
49	li_thread_data_t *tdata;
50
51	if (x == NULL) return;
52
53	tdata = (li_thread_data_t *)x;
54	si_item_release(tdata->thread_item);
55	si_list_release(tdata->thread_list);
56
57	free(tdata);
58}
59
60static void
61_LI_data_free(void *x)
62{
63	struct _li_data_s *t;
64	int i;
65
66	if (x == NULL) return;
67
68	t = (struct _li_data_s *)x;
69
70	for (i = 0; i < t->icount; i++)
71	{
72		_LI_thread_info_free(t->idata[i]);
73		t->idata[i] = NULL;
74	}
75
76	if (t->ikey != NULL) free(t->ikey);
77	t->ikey = NULL;
78
79	if (t->idata != NULL) free(t->idata);
80	t->idata = NULL;
81
82	free(t);
83}
84
85static void
86_LI_data_init()
87{
88	/* _info_key_ok is set to 1 if pthread_key_create succeeded */
89	if (pthread_key_create(&_info_key, _LI_data_free) == 0) _info_key_ok = 1;
90	return;
91}
92
93static struct _li_data_s *
94_LI_data_get()
95{
96	struct _li_data_s *libinfo_data;
97
98	/* only one thread should create the _info_key */
99	pthread_once(&_info_key_initialized, _LI_data_init);
100
101	/* no thread-specific data if pthread_key_create failed */
102	if (_info_key_ok == 0) return NULL;
103
104	/* Check if this thread already created libinfo_data */
105	libinfo_data = pthread_getspecific(_info_key);
106	if (libinfo_data != NULL) return libinfo_data;
107
108	libinfo_data = (struct _li_data_s *)calloc(1, sizeof(struct _li_data_s));
109	if (libinfo_data == NULL) return NULL;
110
111	pthread_setspecific(_info_key, libinfo_data);
112	return libinfo_data;
113}
114
115static li_thread_data_t *
116LI_get_thread_info(uint32_t key)
117{
118	struct _li_data_s *libinfo_data;
119	li_thread_data_t *tdata;
120	uint32_t i, n;
121
122	libinfo_data = _LI_data_get();
123	if (libinfo_data == NULL) return NULL;
124
125	for (i = 0; i < libinfo_data->icount; i++)
126	{
127		if (libinfo_data->ikey[i] == key) return libinfo_data->idata[i];
128	}
129
130	i = libinfo_data->icount;
131	n = i + 1;
132
133	if (i == 0)
134	{
135		libinfo_data->ikey = (uint32_t *)malloc(sizeof(uint32_t));
136		libinfo_data->idata = (void **)malloc(sizeof(void *));
137	}
138	else
139	{
140		libinfo_data->ikey = (uint32_t *)reallocf(libinfo_data->ikey, n * sizeof(uint32_t));
141		libinfo_data->idata = (void **)reallocf(libinfo_data->idata, n * sizeof(void *));
142	}
143
144	if ((libinfo_data->ikey == NULL) || (libinfo_data->idata == NULL))
145	{
146		if (libinfo_data->ikey != NULL) free(libinfo_data->ikey);
147		libinfo_data->ikey = NULL;
148
149		if (libinfo_data->idata != NULL) free(libinfo_data->idata);
150		libinfo_data->idata = NULL;
151
152		return NULL;
153	}
154
155	tdata = (li_thread_data_t *)calloc(1, sizeof(li_thread_data_t));
156	if (tdata == NULL) return NULL;
157
158	libinfo_data->ikey[i] = key;
159	libinfo_data->idata[i] = tdata;
160	libinfo_data->icount++;
161
162	return tdata;
163}
164
165si_item_t *
166LI_get_thread_item(uint32_t key)
167{
168	li_thread_data_t *tdata;
169
170	tdata = LI_get_thread_info(key);
171	if (tdata == NULL) return NULL;
172
173	return tdata->thread_item;
174}
175
176si_list_t *
177LI_get_thread_list(uint32_t key)
178{
179	li_thread_data_t *tdata;
180
181	tdata = LI_get_thread_info(key);
182	if (tdata == NULL) return NULL;
183
184	return tdata->thread_list;
185}
186
187void
188LI_set_thread_item(uint32_t key, si_item_t *item)
189{
190	li_thread_data_t *tdata;
191
192	tdata = LI_get_thread_info(key);
193	if (tdata == NULL) return;
194
195	si_item_release(tdata->thread_item);
196	tdata->thread_item = item;
197}
198
199void
200LI_set_thread_list(uint32_t key, si_list_t *list)
201{
202	li_thread_data_t *tdata;
203
204	tdata = LI_get_thread_info(key);
205	if (tdata == NULL) return;
206
207	si_list_release(tdata->thread_list);
208
209	si_list_reset(list);
210	tdata->thread_list = list;
211}
212