1 /*
2  * Copyright (C) 2015-2021 Alibaba Group Holding Limited
3  */
4 
5 #include <stdlib.h>
6 #include <string.h>
7 #include <aos/errno.h>
8 
9 #include "internal/pthread.h"
10 
11 typedef struct key_value {
12     pthread_t  thread;
13     const uint32_t  *value;
14 } key_value_t;
15 
16 typedef struct pthread_key_value {
17     key_value_t key_value;
18 
19     struct pthread_key_value *next;
20 } pthread_key_value_t;
21 
22 typedef struct pthread_key_value_head {
23     void (*fun)(void *);
24 
25     pthread_key_value_t *next;
26 } pthread_key_value_head_t;
27 
28 typedef struct pthread_key_list_s {
29     pthread_key_t            key_num;
30     pthread_key_value_head_t head;
31 
32     struct pthread_key_list_s *next;
33 } pthread_key_list_t;
34 
35 pthread_key_list_t pthread_key_list_head;
36 pthread_mutex_t g_pthread_key_lock = PTHREAD_MUTEX_INITIALIZER;
37 
pthread_tsd_dtors(void)38 void pthread_tsd_dtors(void)
39 {
40     pthread_key_list_t   *pthread_key_list_s_c = NULL;
41     pthread_key_value_t **key_value_s_prev     = NULL;
42     pthread_key_value_t  *key_value_s_cur      = NULL;
43     pthread_key_value_t  *key_value_s_del      = NULL;
44 
45     pthread_mutex_lock(&g_pthread_key_lock);
46     pthread_key_list_s_c = &pthread_key_list_head;
47     while (pthread_key_list_s_c != NULL) {
48         key_value_s_cur = pthread_key_list_s_c->head.next;
49         if (key_value_s_cur == NULL) {
50             pthread_key_list_s_c = pthread_key_list_s_c->next;
51             continue;
52         }
53 
54         key_value_s_prev = &pthread_key_list_s_c->head.next;
55 
56         while (key_value_s_cur != NULL) {
57             if (key_value_s_cur->key_value.thread == pthread_self()) {
58                 if (pthread_key_list_s_c->head.fun != NULL) {
59                     pthread_key_list_s_c->head.fun((void *)key_value_s_cur->key_value.value);
60                 }
61 
62                 key_value_s_del = key_value_s_cur;
63                 *key_value_s_prev = key_value_s_cur->next;
64                 key_value_s_cur  = key_value_s_cur->next;
65                 free(key_value_s_del);
66                 continue;
67             }
68 
69             key_value_s_prev = &key_value_s_cur->next;
70             key_value_s_cur  = key_value_s_cur->next;
71         }
72         pthread_key_list_s_c = pthread_key_list_s_c->next;
73     }
74 
75     pthread_mutex_unlock(&g_pthread_key_lock);
76 }
77 
78 
pthread_key_create(pthread_key_t * key,void (* destructor)(void *))79 int pthread_key_create(pthread_key_t *key, void (*destructor)(void*))
80 {
81     pthread_key_list_t *pthread_key_list_s_c = NULL;
82     pthread_key_list_t *pthread_key_list_s_l = NULL;
83 
84     if (key == NULL) {
85         return EINVAL;
86     }
87 
88     pthread_mutex_lock(&g_pthread_key_lock);
89 
90     /* if the key list is empty int pthread_key_list_head to save the first key */
91     if (pthread_key_list_head.key_num == 0) {
92         pthread_key_list_head.key_num = 1;
93         pthread_key_list_head.head.fun = destructor;
94         *key = pthread_key_list_head.key_num;
95     } else {
96         /* if the key list is not empty find the last key and add key */
97         /* find the last key */
98         pthread_key_list_s_c = pthread_key_list_head.next;
99         pthread_key_list_s_l = &pthread_key_list_head;
100         while (pthread_key_list_s_c != NULL) {
101              pthread_key_list_s_l = pthread_key_list_s_c;
102              pthread_key_list_s_c = pthread_key_list_s_c->next;
103         }
104 
105         /* malloc the new key */
106         pthread_key_list_s_c = (pthread_key_list_t *)malloc(sizeof(pthread_key_list_t));
107         if (pthread_key_list_s_c == NULL) {
108             pthread_mutex_unlock(&g_pthread_key_lock);
109             return -1;
110         }
111 
112         /* init the new key */
113         memset(pthread_key_list_s_c, 0, sizeof(pthread_key_list_t));
114 
115         /* insert the key to the end of list */
116         pthread_key_list_s_c->key_num = pthread_key_list_s_l->key_num + 1;
117         pthread_key_list_s_c->head.fun = destructor;
118         pthread_key_list_s_l->next = pthread_key_list_s_c;
119 
120         /* update the key value */
121         *key = pthread_key_list_s_c->key_num;
122     }
123 
124     pthread_mutex_unlock(&g_pthread_key_lock);
125 
126     return 0;
127 }
128 
pthread_setspecific(pthread_key_t key,const void * value)129 int pthread_setspecific(pthread_key_t key, const void *value)
130 {
131     pthread_key_list_t  *pthread_key_list_s_c = NULL;
132     pthread_key_value_t *key_value_s_o        = NULL;
133     pthread_key_value_t *key_value_s          = NULL;
134     pthread_key_value_t *key_value_s_c        = NULL;
135     pthread_key_value_t *key_value_s_l        = NULL;
136     int list_flag  = 0;
137     int value_flag = 0;
138     pthread_t self = pthread_self();
139 
140     pthread_mutex_lock(&g_pthread_key_lock);
141 
142     /* find the key in list */
143     pthread_key_list_s_c = &pthread_key_list_head;
144     while (pthread_key_list_s_c != NULL) {
145          if (pthread_key_list_s_c->key_num == key){
146             list_flag = 1;
147             key_value_s_o = pthread_key_list_s_c->head.next;
148             break;
149          }
150 
151          pthread_key_list_s_c = pthread_key_list_s_c->next;
152     }
153 
154     /* if can not find the key in list, return error */
155     if (list_flag == 0) {
156         pthread_mutex_unlock(&g_pthread_key_lock);
157         return EINVAL;
158     }
159 
160     /* if no value store in the key, create new pthread_key_value_t to save the value */
161     if (key_value_s_o == NULL) {
162         key_value_s = (pthread_key_value_t *)malloc(sizeof(pthread_key_value_t));
163         if (key_value_s == NULL) {
164             pthread_mutex_unlock(&g_pthread_key_lock);;
165             return ENOMEM;
166         }
167 
168         memset(key_value_s, 0, sizeof(pthread_key_value_t));
169 
170         /* save the thread id and value */
171         key_value_s->key_value.value = (uint32_t*)value;
172         key_value_s->key_value.thread = self;
173         key_value_s->next = NULL;
174 
175         /* and pthread_key_value_t to value list */
176         pthread_key_list_s_c->head.next = key_value_s;
177     } else {
178         /* if value store in the key, find the last value and add the new value */
179         /* sreach the value list to find if same thread had save the value */
180         key_value_s_c = key_value_s_o;
181         while (key_value_s_c != NULL) {
182             /* if the same thread had save the value update the value */
183             if (key_value_s_c->key_value.thread == self) {
184                 key_value_s_c->key_value.value = (uint32_t*)value;
185                 value_flag = 1;
186 
187                 break;
188             }
189 
190             key_value_s_l = key_value_s_c;
191             key_value_s_c = key_value_s_c->next;
192         }
193 
194         /* if no same thread had save the value before create new pthread_key_value_t */
195         if (value_flag == 0) {
196             key_value_s = (pthread_key_value_t *)malloc(sizeof(pthread_key_value_t));
197             if (key_value_s == NULL) {
198                 pthread_mutex_unlock(&g_pthread_key_lock);;
199                 return ENOMEM;
200             }
201 
202             memset(key_value_s, 0, sizeof(pthread_key_value_t));
203 
204             /* save current value to pthread_key_value_t */
205             key_value_s->next = key_value_s_l->next;
206             key_value_s->key_value.value = (uint32_t*)value;
207             key_value_s->key_value.thread = self;
208 
209             /* add the value to the list */
210             key_value_s_l->next = key_value_s;
211         }
212     }
213 
214     pthread_mutex_unlock(&g_pthread_key_lock);
215 
216     return 0;
217 }
218 
pthread_getspecific(pthread_key_t key)219 void *pthread_getspecific(pthread_key_t key)
220 {
221     pthread_key_list_t  *pthread_key_list_s_c = NULL;
222     pthread_key_value_t *key_value_s_o        = NULL;
223     pthread_key_value_t *key_value_s_c        = NULL;
224     int list_flag = 0;
225 
226     pthread_mutex_lock(&g_pthread_key_lock);
227 
228     /* find the key in list */
229     pthread_key_list_s_c = &pthread_key_list_head;
230     while (pthread_key_list_s_c != NULL) {
231          if (pthread_key_list_s_c->key_num == key){
232             list_flag = 1;
233             key_value_s_o = pthread_key_list_s_c->head.next;
234             break;
235          }
236 
237          pthread_key_list_s_c = pthread_key_list_s_c->next;
238     }
239 
240     /* if can not find the key in list, or no value store in the key, return NULL */
241     if ((list_flag == 0) || (key_value_s_o == NULL)) {
242         pthread_mutex_unlock(&g_pthread_key_lock);
243         return NULL;
244     }
245 
246     /* search the value list to find the value current thread saved */
247     key_value_s_c = key_value_s_o;
248     while (key_value_s_c != NULL) {
249         if (key_value_s_c->key_value.thread == pthread_self()) {
250             pthread_mutex_unlock(&g_pthread_key_lock);
251             return (void *)key_value_s_c->key_value.value;
252         }
253 
254         key_value_s_c = key_value_s_c->next;
255     }
256 
257     /* if can not find the value current thread saved return NULL */
258     pthread_mutex_unlock(&g_pthread_key_lock);
259     return NULL;
260 }
261 
pthread_key_delete(pthread_key_t key)262 int pthread_key_delete(pthread_key_t key)
263 {
264     pthread_key_list_t  *pthread_key_list_s_c = NULL;
265     pthread_key_list_t  *pthread_key_list_s_l = NULL;
266     pthread_key_value_t *key_value_s_o        = NULL;
267     pthread_key_value_t *key_value_s_c        = NULL;
268     pthread_key_value_t *key_value_s_n        = NULL;
269 
270     int list_flag = 0;
271 
272     pthread_mutex_lock(&g_pthread_key_lock);
273 
274     /* if key saved in pthread_key_list_head */
275     if (pthread_key_list_head.key_num == key) {
276         key_value_s_c = pthread_key_list_head.head.next;
277 
278         /* free the value saved in the key */
279         while (key_value_s_c != NULL) {
280             key_value_s_n = key_value_s_c->next;
281             free(key_value_s_c);
282             key_value_s_c = key_value_s_n;
283         }
284 
285         /* set the list pointer to NULL */
286         pthread_key_list_head.head.next = NULL;
287 
288         /* if no other key save in the list set key_num to 0 */
289         if (pthread_key_list_head.next == NULL) {
290             pthread_key_list_head.key_num = 0;
291         }
292         else /* else copy the next key to the head */
293         {
294             pthread_key_list_s_c = pthread_key_list_head.next;
295             pthread_key_list_head.key_num = pthread_key_list_head.next->key_num;
296             memcpy(&pthread_key_list_head.head, &pthread_key_list_head.next->head,
297                    sizeof(pthread_key_value_head_t));
298             pthread_key_list_head.next = pthread_key_list_head.next->next;
299 
300             free(pthread_key_list_s_c);
301         }
302     }
303     else /* if key is not saved in pthread_key_list_head, find the key in the list */
304     {
305         /* find the key in the list */
306         pthread_key_list_s_c = pthread_key_list_head.next;
307         while (pthread_key_list_s_c != NULL) {
308              if (pthread_key_list_s_c->key_num == key){
309                 key_value_s_o = pthread_key_list_s_c->head.next;
310 
311                 if (pthread_key_list_s_l == NULL) {
312                     pthread_key_list_head.next = pthread_key_list_s_c->next;
313                 } else {
314                     pthread_key_list_s_l->next = pthread_key_list_s_c->next;
315                 }
316 
317                 free(pthread_key_list_s_c);
318 
319                 list_flag = 1;
320                 break;
321              }
322 
323              pthread_key_list_s_l = pthread_key_list_s_c;
324              pthread_key_list_s_c = pthread_key_list_s_c->next;
325         }
326 
327         /* if can not find the key in list return error */
328         if (list_flag == 0) {
329             pthread_mutex_unlock(&g_pthread_key_lock);
330             return EINVAL;
331         }
332 
333         /* if no value saved in the key return */
334         if (key_value_s_o == NULL) {
335             pthread_mutex_unlock(&g_pthread_key_lock);
336             return 0;
337         }
338 
339         key_value_s_c = key_value_s_o;
340         while (key_value_s_c != NULL) {
341             key_value_s_n = key_value_s_c->next;
342             free(key_value_s_c);
343             key_value_s_c = key_value_s_n;
344         }
345     }
346 
347     pthread_mutex_unlock(&g_pthread_key_lock);
348     return 0;
349 }
350