pthread_create.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627
  1. /****************************************************************************
  2. * sched/pthread/pthread_create.c
  3. *
  4. * Copyright (C) 2007-2009, 2011, 2013-2018 Gregory Nutt. All rights
  5. * reserved.
  6. * Author: Gregory Nutt <gnutt@nuttx.org>
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. *
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. * 2. Redistributions in binary form must reproduce the above copyright
  15. * notice, this list of conditions and the following disclaimer in
  16. * the documentation and/or other materials provided with the
  17. * distribution.
  18. * 3. Neither the name NuttX nor the names of its contributors may be
  19. * used to endorse or promote products derived from this software
  20. * without specific prior written permission.
  21. *
  22. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  23. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  24. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  25. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  26. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  27. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  28. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  29. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  30. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  31. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  32. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  33. * POSSIBILITY OF SUCH DAMAGE.
  34. *
  35. ****************************************************************************/
  36. /****************************************************************************
  37. * Included Files
  38. ****************************************************************************/
  39. #include <nuttx/config.h>
  40. #include <sys/types.h>
  41. #include <stdbool.h>
  42. #include <string.h>
  43. #include <pthread.h>
  44. #include <sched.h>
  45. #include <debug.h>
  46. #include <assert.h>
  47. #include <errno.h>
  48. #include <queue.h>
  49. #include <nuttx/sched.h>
  50. #include <nuttx/arch.h>
  51. #include <nuttx/semaphore.h>
  52. #include <nuttx/kmalloc.h>
  53. #include <nuttx/pthread.h>
  54. #include "sched/sched.h"
  55. #include "group/group.h"
  56. #include "clock/clock.h"
  57. #include "pthread/pthread.h"
  58. /****************************************************************************
  59. * Public Data
  60. ****************************************************************************/
  61. /* Default pthread attributes (see include/nuttx/pthread.h). When configured
  62. * to build separate kernel- and user-address spaces, this global is
  63. * duplicated in each address spaced. This copy can only be shared within
  64. * the kernel address space.
  65. */
  66. const pthread_attr_t g_default_pthread_attr = PTHREAD_ATTR_INITIALIZER;
  67. /****************************************************************************
  68. * Private Data
  69. ****************************************************************************/
  70. #if CONFIG_TASK_NAME_SIZE > 0
  71. /* This is the name for name-less pthreads */
  72. static const char g_pthreadname[] = "<pthread>";
  73. #endif
  74. /****************************************************************************
  75. * Private Functions
  76. ****************************************************************************/
  77. /****************************************************************************
  78. * Name: pthread_argsetup
  79. *
  80. * Description:
  81. * This functions sets up parameters in the Task Control Block (TCB) in
  82. * preparation for starting a new thread.
  83. *
  84. * pthread_argsetup() is called from task_init() and nxtask_start() to create
  85. * a new task (with arguments cloned via strdup) or pthread_create() which
  86. * has one argument passed by value (distinguished by the pthread boolean
  87. * argument).
  88. *
  89. * Input Parameters:
  90. * tcb - Address of the new task's TCB
  91. * arg - The argument to provide to the pthread on startup.
  92. *
  93. * Returned Value:
  94. * None
  95. *
  96. ****************************************************************************/
  97. static inline void pthread_argsetup(FAR struct pthread_tcb_s *tcb, pthread_addr_t arg)
  98. {
  99. #if CONFIG_TASK_NAME_SIZE > 0
  100. /* Copy the pthread name into the TCB */
  101. strncpy(tcb->cmn.name, g_pthreadname, CONFIG_TASK_NAME_SIZE);
  102. tcb->cmn.name[CONFIG_TASK_NAME_SIZE] = '\0';
  103. #endif /* CONFIG_TASK_NAME_SIZE */
  104. /* For pthreads, args are strictly pass-by-value; that actual
  105. * type wrapped by pthread_addr_t is unknown.
  106. */
  107. tcb->arg = arg;
  108. }
  109. /****************************************************************************
  110. * Name: pthread_addjoininfo
  111. *
  112. * Description:
  113. * Add a join structure to the local data set.
  114. *
  115. * Input Parameters:
  116. * pjoin
  117. *
  118. * Returned Value:
  119. * None
  120. *
  121. * Assumptions:
  122. * The caller has provided protection from re-entrancy.
  123. *
  124. ****************************************************************************/
  125. static inline void pthread_addjoininfo(FAR struct task_group_s *group,
  126. FAR struct join_s *pjoin)
  127. {
  128. pjoin->next = NULL;
  129. if (!group->tg_jointail)
  130. {
  131. group->tg_joinhead = pjoin;
  132. }
  133. else
  134. {
  135. group->tg_jointail->next = pjoin;
  136. }
  137. group->tg_jointail = pjoin;
  138. }
  139. /****************************************************************************
  140. * Name: pthread_start
  141. *
  142. * Description:
  143. * This function is the low level entry point into the pthread
  144. *
  145. * Input Parameters:
  146. * None
  147. *
  148. ****************************************************************************/
  149. static void pthread_start(void)
  150. {
  151. FAR struct pthread_tcb_s *ptcb = (FAR struct pthread_tcb_s *)this_task();
  152. FAR struct task_group_s *group = ptcb->cmn.group;
  153. FAR struct join_s *pjoin = (FAR struct join_s *)ptcb->joininfo;
  154. pthread_addr_t exit_status;
  155. DEBUGASSERT(group && pjoin);
  156. /* Successfully spawned, add the pjoin to our data set. */
  157. (void)pthread_sem_take(&group->tg_joinsem, false);
  158. pthread_addjoininfo(group, pjoin);
  159. (void)pthread_sem_give(&group->tg_joinsem);
  160. /* Report to the spawner that we successfully started. */
  161. pjoin->started = true;
  162. (void)pthread_sem_give(&pjoin->data_sem);
  163. /* The priority of this thread may have been boosted to avoid priority
  164. * inversion problems. If that is the case, then drop to the correct
  165. * execution priority.
  166. */
  167. if (ptcb->cmn.sched_priority > ptcb->cmn.init_priority)
  168. {
  169. DEBUGVERIFY(nxsched_setpriority(&ptcb->cmn, ptcb->cmn.init_priority));
  170. }
  171. /* Pass control to the thread entry point. In the kernel build this has to
  172. * be handled differently if we are starting a user-space pthread; we have
  173. * to switch to user-mode before calling into the pthread.
  174. */
  175. #if defined(CONFIG_BUILD_PROTECTED) || defined(CONFIG_BUILD_KERNEL)
  176. up_pthread_start(ptcb->cmn.entry.pthread, ptcb->arg);
  177. exit_status = NULL;
  178. #else
  179. exit_status = (*ptcb->cmn.entry.pthread)(ptcb->arg);
  180. #endif
  181. /* The thread has returned (should never happen in the kernel mode case) */
  182. pthread_exit(exit_status);
  183. }
  184. /****************************************************************************
  185. * Public Functions
  186. ****************************************************************************/
  187. /****************************************************************************
  188. * Name: pthread_create
  189. *
  190. * Description:
  191. * This function creates and activates a new thread with a specified
  192. * attributes.
  193. *
  194. * Input Parameters:
  195. * thread
  196. * attr
  197. * start_routine
  198. * arg
  199. *
  200. * Returned Value:
  201. * OK (0) on success; a (non-negated) errno value on failure. The errno
  202. * variable is not set.
  203. *
  204. ****************************************************************************/
  205. int pthread_create(FAR pthread_t *thread, FAR const pthread_attr_t *attr,
  206. pthread_startroutine_t start_routine, pthread_addr_t arg)
  207. {
  208. FAR struct pthread_tcb_s *ptcb;
  209. FAR struct join_s *pjoin;
  210. struct sched_param param;
  211. int policy;
  212. int errcode;
  213. pid_t pid;
  214. int ret;
  215. bool group_joined = false;
  216. /* If attributes were not supplied, use the default attributes */
  217. if (!attr)
  218. {
  219. attr = &g_default_pthread_attr;
  220. }
  221. /* Allocate a TCB for the new task. */
  222. ptcb = (FAR struct pthread_tcb_s *)kmm_zalloc(sizeof(struct pthread_tcb_s));
  223. if (!ptcb)
  224. {
  225. serr("ERROR: Failed to allocate TCB\n");
  226. return ENOMEM;
  227. }
  228. /* Bind the parent's group to the new TCB (we have not yet joined the
  229. * group).
  230. */
  231. ret = group_bind(ptcb);
  232. if (ret < 0)
  233. {
  234. errcode = ENOMEM;
  235. goto errout_with_tcb;
  236. }
  237. #ifdef CONFIG_ARCH_ADDRENV
  238. /* Share the address environment of the parent task group. */
  239. ret = up_addrenv_attach(ptcb->cmn.group, this_task());
  240. if (ret < 0)
  241. {
  242. errcode = -ret;
  243. goto errout_with_tcb;
  244. }
  245. #endif
  246. /* Allocate a detachable structure to support pthread_join logic */
  247. pjoin = (FAR struct join_s *)kmm_zalloc(sizeof(struct join_s));
  248. if (!pjoin)
  249. {
  250. serr("ERROR: Failed to allocate join\n");
  251. errcode = ENOMEM;
  252. goto errout_with_tcb;
  253. }
  254. if (attr->stackaddr)
  255. {
  256. /* Use pre-allocated stack */
  257. ret = up_use_stack((FAR struct tcb_s *)ptcb, attr->stackaddr,
  258. attr->stacksize);
  259. }
  260. else
  261. {
  262. /* Allocate the stack for the TCB */
  263. ret = up_create_stack((FAR struct tcb_s *)ptcb, attr->stacksize,
  264. TCB_FLAG_TTYPE_PTHREAD);
  265. }
  266. if (ret != OK)
  267. {
  268. errcode = ENOMEM;
  269. goto errout_with_join;
  270. }
  271. /* Should we use the priority and scheduler specified in the pthread
  272. * attributes? Or should we use the current thread's priority and
  273. * scheduler?
  274. */
  275. if (attr->inheritsched == PTHREAD_INHERIT_SCHED)
  276. {
  277. /* Get the priority (and any other scheduling parameters) for this
  278. * thread.
  279. */
  280. ret = nxsched_getparam(0, &param);
  281. if (ret < 0)
  282. {
  283. errcode = -ret;
  284. goto errout_with_join;
  285. }
  286. /* Get the scheduler policy for this thread */
  287. policy = nxsched_getscheduler(0);
  288. if (policy < 0)
  289. {
  290. errcode = -policy;
  291. goto errout_with_join;
  292. }
  293. }
  294. else
  295. {
  296. /* Use the scheduler policy and policy the attributes */
  297. policy = attr->policy;
  298. param.sched_priority = attr->priority;
  299. #ifdef CONFIG_SCHED_SPORADIC
  300. param.sched_ss_low_priority = attr->low_priority;
  301. param.sched_ss_max_repl = attr->max_repl;
  302. param.sched_ss_repl_period.tv_sec = attr->repl_period.tv_sec;
  303. param.sched_ss_repl_period.tv_nsec = attr->repl_period.tv_nsec;
  304. param.sched_ss_init_budget.tv_sec = attr->budget.tv_sec;
  305. param.sched_ss_init_budget.tv_nsec = attr->budget.tv_nsec;
  306. #endif
  307. }
  308. #ifdef CONFIG_SCHED_SPORADIC
  309. if (policy == SCHED_SPORADIC)
  310. {
  311. FAR struct sporadic_s *sporadic;
  312. sclock_t repl_ticks;
  313. sclock_t budget_ticks;
  314. /* Convert timespec values to system clock ticks */
  315. (void)clock_time2ticks(&param.sched_ss_repl_period, &repl_ticks);
  316. (void)clock_time2ticks(&param.sched_ss_init_budget, &budget_ticks);
  317. /* The replenishment period must be greater than or equal to the
  318. * budget period.
  319. */
  320. if (repl_ticks < budget_ticks)
  321. {
  322. errcode = EINVAL;
  323. goto errout_with_join;
  324. }
  325. /* Initialize the sporadic policy */
  326. ret = sched_sporadic_initialize(&ptcb->cmn);
  327. if (ret >= 0)
  328. {
  329. sporadic = ptcb->cmn.sporadic;
  330. DEBUGASSERT(sporadic != NULL);
  331. /* Save the sporadic scheduling parameters */
  332. sporadic->hi_priority = param.sched_priority;
  333. sporadic->low_priority = param.sched_ss_low_priority;
  334. sporadic->max_repl = param.sched_ss_max_repl;
  335. sporadic->repl_period = repl_ticks;
  336. sporadic->budget = budget_ticks;
  337. /* And start the first replenishment interval */
  338. ret = sched_sporadic_start(&ptcb->cmn);
  339. }
  340. /* Handle any failures */
  341. if (ret < 0)
  342. {
  343. errcode = -ret;
  344. goto errout_with_join;
  345. }
  346. }
  347. #endif
  348. /* Initialize the task control block */
  349. ret = pthread_schedsetup(ptcb, param.sched_priority, pthread_start,
  350. start_routine);
  351. if (ret != OK)
  352. {
  353. errcode = EBUSY;
  354. goto errout_with_join;
  355. }
  356. #ifdef CONFIG_SMP
  357. /* pthread_schedsetup() will set the affinity mask by inheriting the
  358. * setting from the parent task. We need to override this setting
  359. * with the value from the pthread attributes unless that value is
  360. * zero: Zero is the default value and simply means to inherit the
  361. * parent thread's affinity mask.
  362. */
  363. if (attr->affinity != 0)
  364. {
  365. ptcb->cmn.affinity = attr->affinity;
  366. }
  367. #endif
  368. /* Configure the TCB for a pthread receiving on parameter
  369. * passed by value
  370. */
  371. pthread_argsetup(ptcb, arg);
  372. /* Join the parent's task group */
  373. ret = group_join(ptcb);
  374. if (ret < 0)
  375. {
  376. errcode = ENOMEM;
  377. goto errout_with_join;
  378. }
  379. group_joined = true;
  380. /* Attach the join info to the TCB. */
  381. ptcb->joininfo = (FAR void *)pjoin;
  382. /* Set the appropriate scheduling policy in the TCB */
  383. ptcb->cmn.flags &= ~TCB_FLAG_POLICY_MASK;
  384. switch (policy)
  385. {
  386. default:
  387. DEBUGPANIC();
  388. case SCHED_FIFO:
  389. ptcb->cmn.flags |= TCB_FLAG_SCHED_FIFO;
  390. break;
  391. #if CONFIG_RR_INTERVAL > 0
  392. case SCHED_RR:
  393. ptcb->cmn.flags |= TCB_FLAG_SCHED_RR;
  394. ptcb->cmn.timeslice = MSEC2TICK(CONFIG_RR_INTERVAL);
  395. break;
  396. #endif
  397. #ifdef CONFIG_SCHED_SPORADIC
  398. case SCHED_SPORADIC:
  399. ptcb->cmn.flags |= TCB_FLAG_SCHED_SPORADIC;
  400. break;
  401. #endif
  402. #if 0 /* Not supported */
  403. case SCHED_OTHER:
  404. ptcb->cmn.flags |= TCB_FLAG_SCHED_OTHER;
  405. break;
  406. #endif
  407. }
  408. #ifdef CONFIG_CANCELLATION_POINTS
  409. /* Set the deferred cancellation type */
  410. ptcb->cmn.flags |= TCB_FLAG_CANCEL_DEFERRED;
  411. #endif
  412. /* Get the assigned pid before we start the task (who knows what
  413. * could happen to ptcb after this!). Copy this ID into the join structure
  414. * as well.
  415. */
  416. pid = (int)ptcb->cmn.pid;
  417. pjoin->thread = (pthread_t)pid;
  418. /* Initialize the semaphores in the join structure to zero. */
  419. ret = nxsem_init(&pjoin->data_sem, 0, 0);
  420. if (ret == OK)
  421. {
  422. ret = nxsem_init(&pjoin->exit_sem, 0, 0);
  423. }
  424. if (ret < 0)
  425. {
  426. ret = -ret;
  427. }
  428. /* Thse semaphores are used for signaling and, hence, should not have
  429. * priority inheritance enabled.
  430. */
  431. if (ret == OK)
  432. {
  433. ret = nxsem_setprotocol(&pjoin->data_sem, SEM_PRIO_NONE);
  434. if (ret == OK)
  435. {
  436. ret = nxsem_setprotocol(&pjoin->exit_sem, SEM_PRIO_NONE);
  437. }
  438. if (ret < 0)
  439. {
  440. ret = -ret;
  441. }
  442. }
  443. /* If the priority of the new pthread is lower than the priority of the
  444. * parent thread, then starting the pthread could result in both the
  445. * parent and the pthread to be blocked. This is a recipe for priority
  446. * inversion issues.
  447. *
  448. * We avoid this here by boosting the priority of the (inactive) pthread
  449. * so it has the same priority as the parent thread.
  450. */
  451. if (ret == OK)
  452. {
  453. FAR struct tcb_s *parent = this_task();
  454. DEBUGASSERT(parent != NULL);
  455. if (ptcb->cmn.sched_priority < parent->sched_priority)
  456. {
  457. ret = nxsched_setpriority(&ptcb->cmn, parent->sched_priority);
  458. if (ret < 0)
  459. {
  460. ret = -ret;
  461. }
  462. }
  463. }
  464. /* Then activate the task */
  465. sched_lock();
  466. if (ret == OK)
  467. {
  468. ret = task_activate((FAR struct tcb_s *)ptcb);
  469. if (ret < 0)
  470. {
  471. ret = get_errno();
  472. }
  473. }
  474. if (ret == OK)
  475. {
  476. /* Wait for the task to actually get running and to register
  477. * its join structure.
  478. */
  479. (void)pthread_sem_take(&pjoin->data_sem, false);
  480. /* Return the thread information to the caller */
  481. if (thread)
  482. {
  483. *thread = (pthread_t)pid;
  484. }
  485. if (!pjoin->started)
  486. {
  487. ret = EINVAL;
  488. }
  489. sched_unlock();
  490. (void)nxsem_destroy(&pjoin->data_sem);
  491. }
  492. else
  493. {
  494. sched_unlock();
  495. dq_rem((FAR dq_entry_t *)ptcb, (FAR dq_queue_t *)&g_inactivetasks);
  496. (void)nxsem_destroy(&pjoin->data_sem);
  497. (void)nxsem_destroy(&pjoin->exit_sem);
  498. errcode = EIO;
  499. goto errout_with_join;
  500. }
  501. return ret;
  502. errout_with_join:
  503. sched_kfree(pjoin);
  504. ptcb->joininfo = NULL;
  505. errout_with_tcb:
  506. /* Clear group binding */
  507. if (ptcb && !group_joined)
  508. {
  509. ptcb->cmn.group = NULL;
  510. }
  511. sched_releasetcb((FAR struct tcb_s *)ptcb, TCB_FLAG_TTYPE_PTHREAD);
  512. return errcode;
  513. }