pthread.c 12 KB

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