xref: /nrf52832-nimble/rt-thread/components/libc/pthreads/pthread.c (revision 104654410c56c573564690304ae786df310c91fc)
1*10465441SEvalZero /*
2*10465441SEvalZero  * Copyright (c) 2006-2018, RT-Thread Development Team
3*10465441SEvalZero  *
4*10465441SEvalZero  * SPDX-License-Identifier: Apache-2.0
5*10465441SEvalZero  *
6*10465441SEvalZero  * Change Logs:
7*10465441SEvalZero  * Date           Author       Notes
8*10465441SEvalZero  * 2018-01-26     Bernard      Fix pthread_detach issue for a none-joinable
9*10465441SEvalZero  *                             thread.
10*10465441SEvalZero  */
11*10465441SEvalZero 
12*10465441SEvalZero #include <pthread.h>
13*10465441SEvalZero #include <sched.h>
14*10465441SEvalZero #include "pthread_internal.h"
15*10465441SEvalZero 
pthread_system_init(void)16*10465441SEvalZero int pthread_system_init(void)
17*10465441SEvalZero {
18*10465441SEvalZero     /* initialize key area */
19*10465441SEvalZero     pthread_key_system_init();
20*10465441SEvalZero     /* initialize posix mqueue */
21*10465441SEvalZero     posix_mq_system_init();
22*10465441SEvalZero     /* initialize posix semaphore */
23*10465441SEvalZero     posix_sem_system_init();
24*10465441SEvalZero 
25*10465441SEvalZero     return 0;
26*10465441SEvalZero }
27*10465441SEvalZero INIT_COMPONENT_EXPORT(pthread_system_init);
28*10465441SEvalZero 
_pthread_cleanup(rt_thread_t tid)29*10465441SEvalZero static void _pthread_cleanup(rt_thread_t tid)
30*10465441SEvalZero {
31*10465441SEvalZero     _pthread_data_t *ptd;
32*10465441SEvalZero     ptd = _pthread_get_data(tid);
33*10465441SEvalZero 
34*10465441SEvalZero     /* clear cleanup function */
35*10465441SEvalZero     tid->cleanup = RT_NULL;
36*10465441SEvalZero     if (ptd->attr.detachstate == PTHREAD_CREATE_JOINABLE)
37*10465441SEvalZero     {
38*10465441SEvalZero         rt_sem_release(ptd->joinable_sem);
39*10465441SEvalZero     }
40*10465441SEvalZero     else
41*10465441SEvalZero     {
42*10465441SEvalZero         /* release pthread resource */
43*10465441SEvalZero         pthread_detach(tid);
44*10465441SEvalZero     }
45*10465441SEvalZero }
46*10465441SEvalZero 
pthread_entry_stub(void * parameter)47*10465441SEvalZero static void pthread_entry_stub(void *parameter)
48*10465441SEvalZero {
49*10465441SEvalZero     _pthread_data_t *ptd;
50*10465441SEvalZero     void *value;
51*10465441SEvalZero 
52*10465441SEvalZero     ptd = (_pthread_data_t *)parameter;
53*10465441SEvalZero 
54*10465441SEvalZero     /* execute pthread entry */
55*10465441SEvalZero     value = ptd->thread_entry(ptd->thread_parameter);
56*10465441SEvalZero     /* set value */
57*10465441SEvalZero     ptd->return_value = value;
58*10465441SEvalZero }
59*10465441SEvalZero 
pthread_create(pthread_t * tid,const pthread_attr_t * attr,void * (* start)(void *),void * parameter)60*10465441SEvalZero int pthread_create(pthread_t            *tid,
61*10465441SEvalZero                    const pthread_attr_t *attr,
62*10465441SEvalZero                    void *(*start)(void *), void *parameter)
63*10465441SEvalZero {
64*10465441SEvalZero     int result;
65*10465441SEvalZero     void *stack;
66*10465441SEvalZero     char name[RT_NAME_MAX];
67*10465441SEvalZero     static rt_uint16_t pthread_number = 0;
68*10465441SEvalZero     _pthread_data_t *ptd;
69*10465441SEvalZero 
70*10465441SEvalZero     /* tid shall be provided */
71*10465441SEvalZero     RT_ASSERT(tid != RT_NULL);
72*10465441SEvalZero 
73*10465441SEvalZero     /* allocate posix thread data */
74*10465441SEvalZero     ptd = (_pthread_data_t *)rt_malloc(sizeof(_pthread_data_t));
75*10465441SEvalZero     if (ptd == RT_NULL)
76*10465441SEvalZero         return ENOMEM;
77*10465441SEvalZero     /* clean posix thread data memory */
78*10465441SEvalZero     rt_memset(ptd, 0, sizeof(_pthread_data_t));
79*10465441SEvalZero     ptd->canceled = 0;
80*10465441SEvalZero     ptd->cancelstate = PTHREAD_CANCEL_DISABLE;
81*10465441SEvalZero     ptd->canceltype = PTHREAD_CANCEL_DEFERRED;
82*10465441SEvalZero     ptd->magic = PTHREAD_MAGIC;
83*10465441SEvalZero 
84*10465441SEvalZero     if (attr != RT_NULL)
85*10465441SEvalZero     {
86*10465441SEvalZero         ptd->attr = *attr;
87*10465441SEvalZero     }
88*10465441SEvalZero     else
89*10465441SEvalZero     {
90*10465441SEvalZero         /* use default attribute */
91*10465441SEvalZero         pthread_attr_init(&ptd->attr);
92*10465441SEvalZero     }
93*10465441SEvalZero 
94*10465441SEvalZero     rt_snprintf(name, sizeof(name), "pth%02d", pthread_number ++);
95*10465441SEvalZero     if (ptd->attr.stack_base == 0)
96*10465441SEvalZero     {
97*10465441SEvalZero         stack = (void *)rt_malloc(ptd->attr.stack_size);
98*10465441SEvalZero     }
99*10465441SEvalZero     else
100*10465441SEvalZero     {
101*10465441SEvalZero         stack = (void *)(ptd->attr.stack_base);
102*10465441SEvalZero     }
103*10465441SEvalZero 
104*10465441SEvalZero     if (stack == RT_NULL)
105*10465441SEvalZero     {
106*10465441SEvalZero         rt_free(ptd);
107*10465441SEvalZero 
108*10465441SEvalZero         return ENOMEM;
109*10465441SEvalZero     }
110*10465441SEvalZero 
111*10465441SEvalZero     /* pthread is a static thread object */
112*10465441SEvalZero     ptd->tid = (rt_thread_t) rt_malloc(sizeof(struct rt_thread));
113*10465441SEvalZero     if (ptd->tid == RT_NULL)
114*10465441SEvalZero     {
115*10465441SEvalZero         if (ptd->attr.stack_base == 0)
116*10465441SEvalZero             rt_free(stack);
117*10465441SEvalZero         rt_free(ptd);
118*10465441SEvalZero 
119*10465441SEvalZero         return ENOMEM;
120*10465441SEvalZero     }
121*10465441SEvalZero 
122*10465441SEvalZero     if (ptd->attr.detachstate == PTHREAD_CREATE_JOINABLE)
123*10465441SEvalZero     {
124*10465441SEvalZero         ptd->joinable_sem = rt_sem_create(name, 0, RT_IPC_FLAG_FIFO);
125*10465441SEvalZero         if (ptd->joinable_sem == RT_NULL)
126*10465441SEvalZero         {
127*10465441SEvalZero             if (ptd->attr.stack_base != 0)
128*10465441SEvalZero                 rt_free(stack);
129*10465441SEvalZero             rt_free(ptd);
130*10465441SEvalZero 
131*10465441SEvalZero             return ENOMEM;
132*10465441SEvalZero         }
133*10465441SEvalZero     }
134*10465441SEvalZero     else
135*10465441SEvalZero     {
136*10465441SEvalZero         ptd->joinable_sem = RT_NULL;
137*10465441SEvalZero     }
138*10465441SEvalZero 
139*10465441SEvalZero     /* set parameter */
140*10465441SEvalZero     ptd->thread_entry = start;
141*10465441SEvalZero     ptd->thread_parameter = parameter;
142*10465441SEvalZero 
143*10465441SEvalZero     /* initial this pthread to system */
144*10465441SEvalZero     if (rt_thread_init(ptd->tid, name, pthread_entry_stub, ptd,
145*10465441SEvalZero                        stack, ptd->attr.stack_size,
146*10465441SEvalZero                        ptd->attr.priority, 5) != RT_EOK)
147*10465441SEvalZero     {
148*10465441SEvalZero         if (ptd->attr.stack_base == 0)
149*10465441SEvalZero             rt_free(stack);
150*10465441SEvalZero         if (ptd->joinable_sem != RT_NULL)
151*10465441SEvalZero             rt_sem_delete(ptd->joinable_sem);
152*10465441SEvalZero         rt_free(ptd);
153*10465441SEvalZero 
154*10465441SEvalZero         return EINVAL;
155*10465441SEvalZero     }
156*10465441SEvalZero 
157*10465441SEvalZero     /* set pthread id */
158*10465441SEvalZero     *tid = ptd->tid;
159*10465441SEvalZero 
160*10465441SEvalZero     /* set pthread cleanup function and ptd data */
161*10465441SEvalZero     (*tid)->cleanup = _pthread_cleanup;
162*10465441SEvalZero     (*tid)->user_data = (rt_uint32_t)ptd;
163*10465441SEvalZero 
164*10465441SEvalZero     /* start thread */
165*10465441SEvalZero     result = rt_thread_startup(*tid);
166*10465441SEvalZero     if (result == RT_EOK)
167*10465441SEvalZero         return 0;
168*10465441SEvalZero 
169*10465441SEvalZero     /* start thread failed */
170*10465441SEvalZero     rt_thread_detach(ptd->tid);
171*10465441SEvalZero     if (ptd->attr.stack_base == 0)
172*10465441SEvalZero         rt_free(stack);
173*10465441SEvalZero     if (ptd->joinable_sem != RT_NULL)
174*10465441SEvalZero         rt_sem_delete(ptd->joinable_sem);
175*10465441SEvalZero 
176*10465441SEvalZero     rt_free(ptd);
177*10465441SEvalZero 
178*10465441SEvalZero     return EINVAL;
179*10465441SEvalZero }
180*10465441SEvalZero RTM_EXPORT(pthread_create);
181*10465441SEvalZero 
pthread_detach(pthread_t thread)182*10465441SEvalZero int pthread_detach(pthread_t thread)
183*10465441SEvalZero {
184*10465441SEvalZero     _pthread_data_t *ptd;
185*10465441SEvalZero 
186*10465441SEvalZero     ptd = _pthread_get_data(thread);
187*10465441SEvalZero 
188*10465441SEvalZero     if (ptd->attr.detachstate == PTHREAD_CREATE_DETACHED)
189*10465441SEvalZero     {
190*10465441SEvalZero         /* The implementation has detected that the value specified by thread does not refer
191*10465441SEvalZero          * to a joinable thread.
192*10465441SEvalZero          */
193*10465441SEvalZero         return EINVAL;
194*10465441SEvalZero     }
195*10465441SEvalZero 
196*10465441SEvalZero     if ((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_CLOSE)
197*10465441SEvalZero     {
198*10465441SEvalZero         /* delete joinable semaphore */
199*10465441SEvalZero         if (ptd->joinable_sem != RT_NULL)
200*10465441SEvalZero             rt_sem_delete(ptd->joinable_sem);
201*10465441SEvalZero         /* detach thread object */
202*10465441SEvalZero         rt_thread_detach(ptd->tid);
203*10465441SEvalZero 
204*10465441SEvalZero         /* release thread resource */
205*10465441SEvalZero         if (ptd->attr.stack_base == RT_NULL)
206*10465441SEvalZero         {
207*10465441SEvalZero             /* release thread allocated stack */
208*10465441SEvalZero             rt_free(ptd->tid->stack_addr);
209*10465441SEvalZero         }
210*10465441SEvalZero         else
211*10465441SEvalZero         {
212*10465441SEvalZero             /* clean stack addr pointer */
213*10465441SEvalZero             ptd->tid->stack_addr = RT_NULL;
214*10465441SEvalZero         }
215*10465441SEvalZero 
216*10465441SEvalZero         /*
217*10465441SEvalZero          * if this thread create the local thread data,
218*10465441SEvalZero          * delete it
219*10465441SEvalZero          */
220*10465441SEvalZero         if (ptd->tls != RT_NULL)
221*10465441SEvalZero             rt_free(ptd->tls);
222*10465441SEvalZero         rt_free(ptd->tid);
223*10465441SEvalZero         rt_free(ptd);
224*10465441SEvalZero     }
225*10465441SEvalZero     else
226*10465441SEvalZero     {
227*10465441SEvalZero         rt_enter_critical();
228*10465441SEvalZero         /* change to detach state */
229*10465441SEvalZero         ptd->attr.detachstate = PTHREAD_CREATE_DETACHED;
230*10465441SEvalZero 
231*10465441SEvalZero         /* detach joinable semaphore */
232*10465441SEvalZero         rt_sem_delete(ptd->joinable_sem);
233*10465441SEvalZero         ptd->joinable_sem = RT_NULL;
234*10465441SEvalZero         rt_exit_critical();
235*10465441SEvalZero     }
236*10465441SEvalZero 
237*10465441SEvalZero     return 0;
238*10465441SEvalZero }
239*10465441SEvalZero RTM_EXPORT(pthread_detach);
240*10465441SEvalZero 
pthread_join(pthread_t thread,void ** value_ptr)241*10465441SEvalZero int pthread_join(pthread_t thread, void **value_ptr)
242*10465441SEvalZero {
243*10465441SEvalZero     _pthread_data_t *ptd;
244*10465441SEvalZero     rt_err_t result;
245*10465441SEvalZero 
246*10465441SEvalZero     if (thread == rt_thread_self())
247*10465441SEvalZero     {
248*10465441SEvalZero         /* join self */
249*10465441SEvalZero         return EDEADLK;
250*10465441SEvalZero     }
251*10465441SEvalZero 
252*10465441SEvalZero     ptd = _pthread_get_data(thread);
253*10465441SEvalZero     if (ptd->attr.detachstate == PTHREAD_CREATE_DETACHED)
254*10465441SEvalZero         return EINVAL; /* join on a detached pthread */
255*10465441SEvalZero 
256*10465441SEvalZero     result = rt_sem_take(ptd->joinable_sem, RT_WAITING_FOREVER);
257*10465441SEvalZero     if (result == RT_EOK)
258*10465441SEvalZero     {
259*10465441SEvalZero         /* get return value */
260*10465441SEvalZero         if (value_ptr != RT_NULL)
261*10465441SEvalZero             *value_ptr = ptd->return_value;
262*10465441SEvalZero 
263*10465441SEvalZero         /* release resource */
264*10465441SEvalZero         pthread_detach(thread);
265*10465441SEvalZero     }
266*10465441SEvalZero     else
267*10465441SEvalZero     {
268*10465441SEvalZero         return ESRCH;
269*10465441SEvalZero     }
270*10465441SEvalZero 
271*10465441SEvalZero     return 0;
272*10465441SEvalZero }
273*10465441SEvalZero RTM_EXPORT(pthread_join);
274*10465441SEvalZero 
pthread_exit(void * value)275*10465441SEvalZero void pthread_exit(void *value)
276*10465441SEvalZero {
277*10465441SEvalZero     _pthread_data_t *ptd;
278*10465441SEvalZero     _pthread_cleanup_t *cleanup;
279*10465441SEvalZero     extern _pthread_key_data_t _thread_keys[PTHREAD_KEY_MAX];
280*10465441SEvalZero 
281*10465441SEvalZero     ptd = _pthread_get_data(rt_thread_self());
282*10465441SEvalZero 
283*10465441SEvalZero     rt_enter_critical();
284*10465441SEvalZero     /* disable cancel */
285*10465441SEvalZero     ptd->cancelstate = PTHREAD_CANCEL_DISABLE;
286*10465441SEvalZero     /* set return value */
287*10465441SEvalZero     ptd->return_value = value;
288*10465441SEvalZero     rt_exit_critical();
289*10465441SEvalZero 
290*10465441SEvalZero     /* invoke pushed cleanup */
291*10465441SEvalZero     while (ptd->cleanup != RT_NULL)
292*10465441SEvalZero     {
293*10465441SEvalZero         cleanup = ptd->cleanup;
294*10465441SEvalZero         ptd->cleanup = cleanup->next;
295*10465441SEvalZero 
296*10465441SEvalZero         cleanup->cleanup_func(cleanup->parameter);
297*10465441SEvalZero         /* release this cleanup function */
298*10465441SEvalZero         rt_free(cleanup);
299*10465441SEvalZero     }
300*10465441SEvalZero 
301*10465441SEvalZero     /* destruct thread local key */
302*10465441SEvalZero     if (ptd->tls != RT_NULL)
303*10465441SEvalZero     {
304*10465441SEvalZero         void *data;
305*10465441SEvalZero         rt_uint32_t index;
306*10465441SEvalZero 
307*10465441SEvalZero         for (index = 0; index < PTHREAD_KEY_MAX; index ++)
308*10465441SEvalZero         {
309*10465441SEvalZero             if (_thread_keys[index].is_used)
310*10465441SEvalZero             {
311*10465441SEvalZero                 data = ptd->tls[index];
312*10465441SEvalZero                 if (data)
313*10465441SEvalZero                     _thread_keys[index].destructor(data);
314*10465441SEvalZero             }
315*10465441SEvalZero         }
316*10465441SEvalZero 
317*10465441SEvalZero         /* release tls area */
318*10465441SEvalZero         rt_free(ptd->tls);
319*10465441SEvalZero         ptd->tls = RT_NULL;
320*10465441SEvalZero     }
321*10465441SEvalZero 
322*10465441SEvalZero     if (ptd->attr.detachstate == PTHREAD_CREATE_JOINABLE)
323*10465441SEvalZero     {
324*10465441SEvalZero         /* release the joinable pthread */
325*10465441SEvalZero         rt_sem_release(ptd->joinable_sem);
326*10465441SEvalZero     }
327*10465441SEvalZero 
328*10465441SEvalZero     /* detach thread */
329*10465441SEvalZero     rt_thread_detach(ptd->tid);
330*10465441SEvalZero     /* reschedule thread */
331*10465441SEvalZero     rt_schedule();
332*10465441SEvalZero }
333*10465441SEvalZero RTM_EXPORT(pthread_exit);
334*10465441SEvalZero 
pthread_once(pthread_once_t * once_control,void (* init_routine)(void))335*10465441SEvalZero int pthread_once(pthread_once_t *once_control, void (*init_routine)(void))
336*10465441SEvalZero {
337*10465441SEvalZero     RT_ASSERT(once_control != RT_NULL);
338*10465441SEvalZero     RT_ASSERT(init_routine != RT_NULL);
339*10465441SEvalZero 
340*10465441SEvalZero     rt_enter_critical();
341*10465441SEvalZero     if (!(*once_control))
342*10465441SEvalZero     {
343*10465441SEvalZero         /* call routine once */
344*10465441SEvalZero         *once_control = 1;
345*10465441SEvalZero         rt_exit_critical();
346*10465441SEvalZero 
347*10465441SEvalZero         init_routine();
348*10465441SEvalZero     }
349*10465441SEvalZero     rt_exit_critical();
350*10465441SEvalZero 
351*10465441SEvalZero     return 0;
352*10465441SEvalZero }
353*10465441SEvalZero RTM_EXPORT(pthread_once);
354*10465441SEvalZero 
pthread_atfork(void (* prepare)(void),void (* parent)(void),void (* child)(void))355*10465441SEvalZero int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void))
356*10465441SEvalZero {
357*10465441SEvalZero     return EOPNOTSUPP;
358*10465441SEvalZero }
359*10465441SEvalZero RTM_EXPORT(pthread_atfork);
360*10465441SEvalZero 
pthread_kill(pthread_t thread,int sig)361*10465441SEvalZero int pthread_kill(pthread_t thread, int sig)
362*10465441SEvalZero {
363*10465441SEvalZero #ifdef RT_USING_SIGNALS
364*10465441SEvalZero     return rt_thread_kill(thread, sig);
365*10465441SEvalZero #else
366*10465441SEvalZero     return ENOSYS;
367*10465441SEvalZero #endif
368*10465441SEvalZero }
369*10465441SEvalZero RTM_EXPORT(pthread_kill);
370*10465441SEvalZero 
371*10465441SEvalZero #ifdef RT_USING_SIGNALS
pthread_sigmask(int how,const sigset_t * set,sigset_t * oset)372*10465441SEvalZero int pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
373*10465441SEvalZero {
374*10465441SEvalZero     return sigprocmask(how, set, oset);
375*10465441SEvalZero }
376*10465441SEvalZero #endif
377*10465441SEvalZero 
pthread_cleanup_pop(int execute)378*10465441SEvalZero void pthread_cleanup_pop(int execute)
379*10465441SEvalZero {
380*10465441SEvalZero     _pthread_data_t *ptd;
381*10465441SEvalZero     _pthread_cleanup_t *cleanup;
382*10465441SEvalZero 
383*10465441SEvalZero     /* get posix thread data */
384*10465441SEvalZero     ptd = _pthread_get_data(rt_thread_self());
385*10465441SEvalZero     RT_ASSERT(ptd != RT_NULL);
386*10465441SEvalZero 
387*10465441SEvalZero     if (execute)
388*10465441SEvalZero     {
389*10465441SEvalZero         rt_enter_critical();
390*10465441SEvalZero         cleanup = ptd->cleanup;
391*10465441SEvalZero         if (cleanup)
392*10465441SEvalZero             ptd->cleanup = cleanup->next;
393*10465441SEvalZero         rt_exit_critical();
394*10465441SEvalZero 
395*10465441SEvalZero         if (cleanup)
396*10465441SEvalZero         {
397*10465441SEvalZero             cleanup->cleanup_func(cleanup->parameter);
398*10465441SEvalZero 
399*10465441SEvalZero             rt_free(cleanup);
400*10465441SEvalZero         }
401*10465441SEvalZero     }
402*10465441SEvalZero }
403*10465441SEvalZero RTM_EXPORT(pthread_cleanup_pop);
404*10465441SEvalZero 
pthread_cleanup_push(void (* routine)(void *),void * arg)405*10465441SEvalZero void pthread_cleanup_push(void (*routine)(void *), void *arg)
406*10465441SEvalZero {
407*10465441SEvalZero     _pthread_data_t *ptd;
408*10465441SEvalZero     _pthread_cleanup_t *cleanup;
409*10465441SEvalZero 
410*10465441SEvalZero     /* get posix thread data */
411*10465441SEvalZero     ptd = _pthread_get_data(rt_thread_self());
412*10465441SEvalZero     RT_ASSERT(ptd != RT_NULL);
413*10465441SEvalZero 
414*10465441SEvalZero     cleanup = (_pthread_cleanup_t *)rt_malloc(sizeof(_pthread_cleanup_t));
415*10465441SEvalZero     if (cleanup != RT_NULL)
416*10465441SEvalZero     {
417*10465441SEvalZero         cleanup->cleanup_func = routine;
418*10465441SEvalZero         cleanup->parameter = arg;
419*10465441SEvalZero 
420*10465441SEvalZero         rt_enter_critical();
421*10465441SEvalZero         cleanup->next = ptd->cleanup;
422*10465441SEvalZero         ptd->cleanup = cleanup;
423*10465441SEvalZero         rt_exit_critical();
424*10465441SEvalZero     }
425*10465441SEvalZero }
426*10465441SEvalZero RTM_EXPORT(pthread_cleanup_push);
427*10465441SEvalZero 
428*10465441SEvalZero /*
429*10465441SEvalZero  * According to IEEE Std 1003.1, 2004 Edition , following pthreads
430*10465441SEvalZero  * interface support cancellation point:
431*10465441SEvalZero  * mq_receive()
432*10465441SEvalZero  * mq_send()
433*10465441SEvalZero  * mq_timedreceive()
434*10465441SEvalZero  * mq_timedsend()
435*10465441SEvalZero  * msgrcv()
436*10465441SEvalZero  * msgsnd()
437*10465441SEvalZero  * msync()
438*10465441SEvalZero  * pthread_cond_timedwait()
439*10465441SEvalZero  * pthread_cond_wait()
440*10465441SEvalZero  * pthread_join()
441*10465441SEvalZero  * pthread_testcancel()
442*10465441SEvalZero  * sem_timedwait()
443*10465441SEvalZero  * sem_wait()
444*10465441SEvalZero  *
445*10465441SEvalZero  * A cancellation point may also occur when a thread is
446*10465441SEvalZero  * executing the following functions:
447*10465441SEvalZero  * pthread_rwlock_rdlock()
448*10465441SEvalZero  * pthread_rwlock_timedrdlock()
449*10465441SEvalZero  * pthread_rwlock_timedwrlock()
450*10465441SEvalZero  * pthread_rwlock_wrlock()
451*10465441SEvalZero  *
452*10465441SEvalZero  * The pthread_cancel(), pthread_setcancelstate(), and pthread_setcanceltype()
453*10465441SEvalZero  * functions are defined to be async-cancel safe.
454*10465441SEvalZero  */
455*10465441SEvalZero 
pthread_setcancelstate(int state,int * oldstate)456*10465441SEvalZero int pthread_setcancelstate(int state, int *oldstate)
457*10465441SEvalZero {
458*10465441SEvalZero     _pthread_data_t *ptd;
459*10465441SEvalZero 
460*10465441SEvalZero     /* get posix thread data */
461*10465441SEvalZero     ptd = _pthread_get_data(rt_thread_self());
462*10465441SEvalZero     RT_ASSERT(ptd != RT_NULL);
463*10465441SEvalZero 
464*10465441SEvalZero     if ((state == PTHREAD_CANCEL_ENABLE) || (state == PTHREAD_CANCEL_DISABLE))
465*10465441SEvalZero     {
466*10465441SEvalZero         if (oldstate)
467*10465441SEvalZero             *oldstate = ptd->cancelstate;
468*10465441SEvalZero         ptd->cancelstate = state;
469*10465441SEvalZero 
470*10465441SEvalZero         return 0;
471*10465441SEvalZero     }
472*10465441SEvalZero 
473*10465441SEvalZero     return EINVAL;
474*10465441SEvalZero }
475*10465441SEvalZero RTM_EXPORT(pthread_setcancelstate);
476*10465441SEvalZero 
pthread_setcanceltype(int type,int * oldtype)477*10465441SEvalZero int pthread_setcanceltype(int type, int *oldtype)
478*10465441SEvalZero {
479*10465441SEvalZero     _pthread_data_t *ptd;
480*10465441SEvalZero 
481*10465441SEvalZero     /* get posix thread data */
482*10465441SEvalZero     ptd = _pthread_get_data(rt_thread_self());
483*10465441SEvalZero     RT_ASSERT(ptd != RT_NULL);
484*10465441SEvalZero 
485*10465441SEvalZero     if ((type != PTHREAD_CANCEL_DEFERRED) && (type != PTHREAD_CANCEL_ASYNCHRONOUS))
486*10465441SEvalZero         return EINVAL;
487*10465441SEvalZero 
488*10465441SEvalZero     if (oldtype)
489*10465441SEvalZero         *oldtype = ptd->canceltype;
490*10465441SEvalZero     ptd->canceltype = type;
491*10465441SEvalZero 
492*10465441SEvalZero     return 0;
493*10465441SEvalZero }
494*10465441SEvalZero RTM_EXPORT(pthread_setcanceltype);
495*10465441SEvalZero 
pthread_testcancel(void)496*10465441SEvalZero void pthread_testcancel(void)
497*10465441SEvalZero {
498*10465441SEvalZero     int cancel = 0;
499*10465441SEvalZero     _pthread_data_t *ptd;
500*10465441SEvalZero 
501*10465441SEvalZero     /* get posix thread data */
502*10465441SEvalZero     ptd = _pthread_get_data(rt_thread_self());
503*10465441SEvalZero     RT_ASSERT(ptd != RT_NULL);
504*10465441SEvalZero 
505*10465441SEvalZero     if (ptd->cancelstate == PTHREAD_CANCEL_ENABLE)
506*10465441SEvalZero         cancel = ptd->canceled;
507*10465441SEvalZero     if (cancel)
508*10465441SEvalZero         pthread_exit((void *)PTHREAD_CANCELED);
509*10465441SEvalZero }
510*10465441SEvalZero RTM_EXPORT(pthread_testcancel);
511*10465441SEvalZero 
pthread_cancel(pthread_t thread)512*10465441SEvalZero int pthread_cancel(pthread_t thread)
513*10465441SEvalZero {
514*10465441SEvalZero     _pthread_data_t *ptd;
515*10465441SEvalZero 
516*10465441SEvalZero     /* cancel self */
517*10465441SEvalZero     if (thread == rt_thread_self())
518*10465441SEvalZero         return 0;
519*10465441SEvalZero 
520*10465441SEvalZero     /* get posix thread data */
521*10465441SEvalZero     ptd = _pthread_get_data(thread);
522*10465441SEvalZero     RT_ASSERT(ptd != RT_NULL);
523*10465441SEvalZero 
524*10465441SEvalZero     /* set canceled */
525*10465441SEvalZero     if (ptd->cancelstate == PTHREAD_CANCEL_ENABLE)
526*10465441SEvalZero     {
527*10465441SEvalZero         ptd->canceled = 1;
528*10465441SEvalZero         if (ptd->canceltype == PTHREAD_CANCEL_ASYNCHRONOUS)
529*10465441SEvalZero         {
530*10465441SEvalZero             /*
531*10465441SEvalZero              * to detach thread.
532*10465441SEvalZero              * this thread will be removed from scheduler list
533*10465441SEvalZero              * and because there is a cleanup function in the
534*10465441SEvalZero              * thread (pthread_cleanup), it will move to defunct
535*10465441SEvalZero              * thread list and wait for handling in idle thread.
536*10465441SEvalZero              */
537*10465441SEvalZero             rt_thread_detach(thread);
538*10465441SEvalZero         }
539*10465441SEvalZero     }
540*10465441SEvalZero 
541*10465441SEvalZero     return 0;
542*10465441SEvalZero }
543*10465441SEvalZero RTM_EXPORT(pthread_cancel);
544