threadobj.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593
  1. /*
  2. * Copyright (C) 2008 Philippe Gerum <rpm@xenomai.org>.
  3. *
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Lesser General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2 of the License, or (at your option) any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Lesser General Public License for more details.
  13. * You should have received a copy of the GNU Lesser General Public
  14. * License along with this library; if not, write to the Free Software
  15. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  16. */
  17. #ifndef _COPPERPLATE_THREADOBJ_H
  18. #define _COPPERPLATE_THREADOBJ_H
  19. #include <time.h>
  20. #include <semaphore.h>
  21. #include <signal.h>
  22. #include <pthread.h>
  23. #include <stdint.h>
  24. #include <boilerplate/list.h>
  25. #include <boilerplate/lock.h>
  26. #include <boilerplate/sched.h>
  27. #include <copperplate/clockobj.h>
  28. #include <copperplate/heapobj.h>
  29. #ifdef CONFIG_XENO_COBALT
  30. #include <cobalt/uapi/kernel/types.h>
  31. struct xnthread_user_window;
  32. struct threadobj_corespec {
  33. xnhandle_t handle;
  34. union {
  35. __u32 u_winoff;
  36. struct xnthread_user_window *u_window;
  37. };
  38. };
  39. struct threadobj_stat {
  40. /** Execution time in primary mode (ns). */
  41. ticks_t xtime;
  42. /** Current timeout value (ns). */
  43. ticks_t timeout;
  44. /** Number of primary->secondary mode switches. */
  45. uint64_t msw;
  46. /** Number of context switches. */
  47. uint64_t csw;
  48. /** Number of Xenomai syscalls. */
  49. uint64_t xsc;
  50. /** Current CPU for thread. */
  51. int cpu;
  52. /** Scheduler lock nesting count. */
  53. int schedlock;
  54. /** Cobalt thread status bits. */
  55. unsigned int status;
  56. /** Number of page faults. */
  57. uint32_t pf;
  58. };
  59. #define SCHED_CORE SCHED_COBALT
  60. static inline
  61. void threadobj_save_timeout(struct threadobj_corespec *corespec,
  62. const struct timespec *timeout)
  63. {
  64. /*
  65. * We retrieve this information from the nucleus directly via
  66. * cobalt_thread_stat().
  67. */
  68. }
  69. #ifdef CONFIG_XENO_PSHARED
  70. static inline struct xnthread_user_window *
  71. threadobj_get_window(struct threadobj_corespec *corespec)
  72. {
  73. extern void *cobalt_umm_shared;
  74. return (struct xnthread_user_window *)
  75. ((caddr_t)cobalt_umm_shared + corespec->u_winoff);
  76. }
  77. #else /* !CONFIG_XENO_PSHARED */
  78. static inline struct xnthread_user_window *
  79. threadobj_get_window(struct threadobj_corespec *corespec)
  80. {
  81. return corespec->u_window;
  82. }
  83. #endif /* !CONFIG_XENO_PSHARED */
  84. #else /* CONFIG_XENO_MERCURY */
  85. #include <sys/time.h>
  86. struct threadobj_corespec {
  87. pthread_cond_t grant_sync;
  88. int policy_unlocked;
  89. struct sched_param_ex schedparam_unlocked;
  90. timer_t rr_timer;
  91. /** Timeout reported by sysregd. */
  92. struct timespec timeout;
  93. #ifdef CONFIG_XENO_WORKAROUND_CONDVAR_PI
  94. int policy_unboosted;
  95. struct sched_param_ex schedparam_unboosted;
  96. #endif
  97. };
  98. struct threadobj_stat {
  99. /** Current timeout value (ns). */
  100. ticks_t timeout;
  101. /** Current CPU for thread. */
  102. int cpu;
  103. /** Scheduler lock nesting count. */
  104. int schedlock;
  105. /** Mercury thread status bits. */
  106. unsigned int status;
  107. };
  108. #define SCHED_CORE SCHED_FIFO
  109. static inline
  110. void threadobj_save_timeout(struct threadobj_corespec *corespec,
  111. const struct timespec *timeout)
  112. {
  113. if (timeout)
  114. corespec->timeout = *timeout;
  115. }
  116. #endif /* CONFIG_XENO_MERCURY */
  117. /*
  118. * threadobj->status, updated with ->lock held.
  119. */
  120. #define __THREAD_S_STARTED (1 << 0) /* threadobj_start() called. */
  121. #define __THREAD_S_WARMUP (1 << 1) /* threadobj_prologue() not called yet. */
  122. #define __THREAD_S_ABORTED (1 << 2) /* Cancelled before start. */
  123. #define __THREAD_S_LOCKED (1 << 3) /* threadobj_lock() granted (debug only). */
  124. #define __THREAD_S_ACTIVE (1 << 4) /* Running user code. */
  125. #define __THREAD_S_SUSPENDED (1 << 5) /* Suspended via threadobj_suspend(). */
  126. #define __THREAD_S_SAFE (1 << 6) /* TCB release deferred. */
  127. #define __THREAD_S_PERIODIC (1 << 7) /* Periodic timer set. */
  128. #define __THREAD_S_DEBUG (1 << 31) /* Debug mode enabled. */
  129. /*
  130. * threadobj->run_state, locklessly updated by "current", merged
  131. * with ->status bits by threadobj_get_status().
  132. */
  133. #define __THREAD_S_RUNNING 0
  134. #define __THREAD_S_DORMANT (1 << 16)
  135. #define __THREAD_S_WAIT (1 << 17)
  136. #define __THREAD_S_TIMEDWAIT (1 << 18)
  137. #define __THREAD_S_DELAYED (1 << 19)
  138. #define __THREAD_S_BREAK (__THREAD_S_DELAYED|(1 << 20))
  139. /* threadobj mode bits */
  140. #define __THREAD_M_LOCK (1 << 0) /* Toggle scheduler lock. */
  141. #define __THREAD_M_WARNSW (1 << 1) /* Toggle switch warning bit. */
  142. #define __THREAD_M_CONFORMING (1 << 2) /* Switch to conforming mode. */
  143. #define __THREAD_M_SPARE0 (1 << 16)
  144. #define __THREAD_M_SPARE1 (1 << 17)
  145. #define __THREAD_M_SPARE2 (1 << 18)
  146. #define __THREAD_M_SPARE3 (1 << 19)
  147. #define __THREAD_M_SPARE4 (1 << 20)
  148. #define __THREAD_M_SPARE5 (1 << 21)
  149. #define __THREAD_M_SPARE6 (1 << 22)
  150. #define __THREAD_M_SPARE7 (1 << 23)
  151. /*
  152. * We need to use a valid address here. The object will never be dereferenced
  153. * when it is identified as IRQ context, so the pthread key itself is fine.
  154. */
  155. #define THREADOBJ_IRQCONTEXT ((struct threadobj *)&threadobj_tskey)
  156. struct traceobj;
  157. struct syncobj;
  158. struct threadobj {
  159. unsigned int magic; /* Must be first. */
  160. pthread_t ptid;
  161. pthread_mutex_t lock;
  162. int schedlock_depth;
  163. int cancel_state;
  164. int status;
  165. int run_state;
  166. int policy;
  167. struct sched_param_ex schedparam;
  168. int global_priority;
  169. pid_t cnode;
  170. pid_t pid;
  171. char name[32];
  172. void (*finalizer)(struct threadobj *thobj);
  173. int core_offset;
  174. int *errno_pointer;
  175. /* Those members belong exclusively to the syncobj code. */
  176. struct syncobj *wait_sobj;
  177. struct holder wait_link;
  178. int wait_status;
  179. int wait_prio;
  180. dref_type(void *) wait_union;
  181. size_t wait_size;
  182. timer_t periodic_timer;
  183. struct threadobj_corespec core;
  184. struct timespec tslice;
  185. pthread_cond_t barrier;
  186. struct traceobj *tracer;
  187. sem_t *cancel_sem;
  188. struct sysgroup_memspec memspec;
  189. struct backtrace_data btd;
  190. };
  191. struct threadobj_init_data {
  192. unsigned int magic;
  193. cpu_set_t affinity;
  194. int policy;
  195. struct sched_param_ex param_ex;
  196. void (*finalizer)(struct threadobj *thobj);
  197. };
  198. extern int threadobj_high_prio;
  199. extern int threadobj_irq_prio;
  200. extern pthread_key_t threadobj_tskey;
  201. #ifdef HAVE_TLS
  202. extern __thread __attribute__ ((tls_model (CONFIG_XENO_TLS_MODEL)))
  203. struct threadobj *__threadobj_current;
  204. static inline void threadobj_set_current(struct threadobj *thobj)
  205. {
  206. __threadobj_current = thobj;
  207. pthread_setspecific(threadobj_tskey, thobj);
  208. }
  209. static inline struct threadobj *__threadobj_get_current(void)
  210. {
  211. return __threadobj_current;
  212. }
  213. #else /* !HAVE_TLS */
  214. static inline void threadobj_set_current(struct threadobj *thobj)
  215. {
  216. pthread_setspecific(threadobj_tskey, thobj);
  217. }
  218. static inline struct threadobj *__threadobj_get_current(void)
  219. {
  220. return (struct threadobj *)pthread_getspecific(threadobj_tskey);
  221. }
  222. #endif /* !HAVE_TLS */
  223. static inline struct threadobj *threadobj_current(void)
  224. {
  225. struct threadobj *thobj = __threadobj_get_current();
  226. return thobj == NULL || thobj == THREADOBJ_IRQCONTEXT ? NULL : thobj;
  227. }
  228. #ifdef CONFIG_XENO_DEBUG
  229. static inline void __threadobj_tag_locked(struct threadobj *thobj)
  230. {
  231. thobj->status |= __THREAD_S_LOCKED;
  232. }
  233. static inline void __threadobj_tag_unlocked(struct threadobj *thobj)
  234. {
  235. assert(thobj->status & __THREAD_S_LOCKED);
  236. thobj->status &= ~__THREAD_S_LOCKED;
  237. }
  238. static inline void __threadobj_check_locked(struct threadobj *thobj)
  239. {
  240. assert(thobj->status & __THREAD_S_LOCKED);
  241. }
  242. #else /* !CONFIG_XENO_DEBUG */
  243. static inline void __threadobj_tag_locked(struct threadobj *thobj)
  244. {
  245. }
  246. static inline void __threadobj_tag_unlocked(struct threadobj *thobj)
  247. {
  248. }
  249. static inline void __threadobj_check_locked(struct threadobj *thobj)
  250. {
  251. }
  252. #endif /* !CONFIG_XENO_DEBUG */
  253. #ifdef __cplusplus
  254. extern "C" {
  255. #endif
  256. void *__threadobj_alloc(size_t tcb_struct_size,
  257. size_t wait_union_size,
  258. int thobj_offset);
  259. static inline void __threadobj_free(void *p)
  260. {
  261. xnfree(p);
  262. }
  263. static inline void threadobj_free(struct threadobj *thobj)
  264. {
  265. __threadobj_free((unsigned char *)thobj - thobj->core_offset);
  266. }
  267. int threadobj_init(struct threadobj *thobj,
  268. struct threadobj_init_data *idata) __must_check;
  269. int threadobj_start(struct threadobj *thobj) __must_check;
  270. int threadobj_shadow(struct threadobj *thobj,
  271. const char *name);
  272. int threadobj_prologue(struct threadobj *thobj,
  273. const char *name);
  274. void threadobj_wait_start(void);
  275. void threadobj_notify_entry(void);
  276. int threadobj_cancel(struct threadobj *thobj);
  277. void threadobj_uninit(struct threadobj *thobj);
  278. int threadobj_suspend(struct threadobj *thobj);
  279. int threadobj_resume(struct threadobj *thobj);
  280. int threadobj_unblock(struct threadobj *thobj);
  281. int __threadobj_lock_sched(struct threadobj *current);
  282. int threadobj_lock_sched(void);
  283. int __threadobj_unlock_sched(struct threadobj *current);
  284. int threadobj_unlock_sched(void);
  285. int threadobj_set_schedparam(struct threadobj *thobj, int policy,
  286. const struct sched_param_ex *param_ex);
  287. int threadobj_set_schedprio(struct threadobj *thobj, int priority);
  288. int threadobj_set_mode(int clrmask, int setmask, int *mode_r);
  289. int threadobj_set_periodic(struct threadobj *thobj,
  290. const struct timespec *__restrict__ idate,
  291. const struct timespec *__restrict__ period);
  292. int threadobj_get_periodic(struct threadobj *thobj,
  293. struct timespec *__restrict__ idate,
  294. struct timespec *__restrict__ period);
  295. int threadobj_wait_period(unsigned long *overruns_r) __must_check;
  296. void threadobj_spin(ticks_t ns);
  297. int threadobj_stat(struct threadobj *thobj,
  298. struct threadobj_stat *stat);
  299. int threadobj_sleep(const struct timespec *ts);
  300. void threadobj_set_current_name(const char *name);
  301. #ifdef CONFIG_XENO_PSHARED
  302. static inline int threadobj_local_p(struct threadobj *thobj)
  303. {
  304. extern pid_t __node_id;
  305. return thobj->cnode == __node_id;
  306. }
  307. #else /* !CONFIG_XENO_PSHARED */
  308. static inline int threadobj_local_p(struct threadobj *thobj)
  309. {
  310. return 1;
  311. }
  312. #endif /* !CONFIG_XENO_PSHARED */
  313. void threadobj_init_key(void);
  314. int threadobj_pkg_init(int anon_session);
  315. #ifdef __cplusplus
  316. }
  317. #endif
  318. #define threadobj_alloc(T, __mptr, W) \
  319. ({ \
  320. void *__p; \
  321. __p = __threadobj_alloc(sizeof(T), sizeof(W), offsetof(T, __mptr)); \
  322. __p; \
  323. })
  324. static inline int threadobj_get_policy(struct threadobj *thobj)
  325. {
  326. return thobj->policy;
  327. }
  328. static inline int threadobj_get_priority(struct threadobj *thobj)
  329. {
  330. return thobj->schedparam.sched_priority;
  331. }
  332. static inline void threadobj_copy_schedparam(struct sched_param_ex *param_ex,
  333. const struct threadobj *thobj)
  334. {
  335. *param_ex = thobj->schedparam;
  336. }
  337. static inline int threadobj_lock(struct threadobj *thobj)
  338. {
  339. int ret;
  340. ret = write_lock_safe(&thobj->lock, thobj->cancel_state);
  341. if (ret)
  342. return ret;
  343. __threadobj_tag_locked(thobj);
  344. return 0;
  345. }
  346. static inline int threadobj_trylock(struct threadobj *thobj)
  347. {
  348. int ret;
  349. ret = write_trylock_safe(&thobj->lock, thobj->cancel_state);
  350. if (ret)
  351. return ret;
  352. __threadobj_tag_locked(thobj);
  353. return 0;
  354. }
  355. static inline int threadobj_unlock(struct threadobj *thobj)
  356. {
  357. __threadobj_check_locked(thobj);
  358. __threadobj_tag_unlocked(thobj);
  359. return write_unlock_safe(&thobj->lock, thobj->cancel_state);
  360. }
  361. static inline int threadobj_irq_p(void)
  362. {
  363. struct threadobj *current = __threadobj_get_current();
  364. return current == THREADOBJ_IRQCONTEXT;
  365. }
  366. static inline int threadobj_current_p(void)
  367. {
  368. return threadobj_current() != NULL;
  369. }
  370. static inline int __threadobj_lock_sched_once(struct threadobj *current)
  371. {
  372. if (current->schedlock_depth == 0)
  373. return __threadobj_lock_sched(current);
  374. return -EBUSY;
  375. }
  376. static inline int threadobj_lock_sched_once(void)
  377. {
  378. struct threadobj *current = threadobj_current();
  379. if (current->schedlock_depth == 0)
  380. return threadobj_lock_sched();
  381. return -EBUSY;
  382. }
  383. static inline void threadobj_yield(void)
  384. {
  385. __RT(sched_yield());
  386. }
  387. static inline unsigned int threadobj_get_magic(struct threadobj *thobj)
  388. {
  389. return thobj->magic;
  390. }
  391. static inline void threadobj_set_magic(struct threadobj *thobj,
  392. unsigned int magic)
  393. {
  394. thobj->magic = magic;
  395. }
  396. static inline int threadobj_get_lockdepth(struct threadobj *thobj)
  397. {
  398. return thobj->schedlock_depth;
  399. }
  400. static inline int threadobj_get_status(struct threadobj *thobj)
  401. {
  402. return thobj->status | thobj->run_state;
  403. }
  404. static inline int threadobj_get_errno(struct threadobj *thobj)
  405. {
  406. return *thobj->errno_pointer;
  407. }
  408. #define threadobj_prepare_wait(T) \
  409. ({ \
  410. struct threadobj *__thobj = threadobj_current(); \
  411. assert(__thobj != NULL); \
  412. assert(sizeof(typeof(T)) <= __thobj->wait_size); \
  413. __mptr(__thobj->wait_union); \
  414. })
  415. #define threadobj_finish_wait() do { } while (0)
  416. static inline void *threadobj_get_wait(struct threadobj *thobj)
  417. {
  418. return __mptr(thobj->wait_union);
  419. }
  420. static inline const char *threadobj_get_name(struct threadobj *thobj)
  421. {
  422. return thobj->name;
  423. }
  424. static inline pid_t threadobj_get_pid(struct threadobj *thobj)
  425. {
  426. return thobj->pid;
  427. }
  428. #ifdef CONFIG_XENO_WORKAROUND_CONDVAR_PI
  429. int threadobj_cond_timedwait(pthread_cond_t *cond,
  430. pthread_mutex_t *lock,
  431. const struct timespec *timeout);
  432. int threadobj_cond_wait(pthread_cond_t *cond,
  433. pthread_mutex_t *lock);
  434. int threadobj_cond_signal(pthread_cond_t *cond);
  435. int threadobj_cond_broadcast(pthread_cond_t *cond);
  436. #else
  437. static inline
  438. int threadobj_cond_timedwait(pthread_cond_t *cond,
  439. pthread_mutex_t *lock,
  440. const struct timespec *timeout)
  441. {
  442. return __RT(pthread_cond_timedwait(cond, lock, timeout));
  443. }
  444. static inline
  445. int threadobj_cond_wait(pthread_cond_t *cond,
  446. pthread_mutex_t *lock)
  447. {
  448. return __RT(pthread_cond_wait(cond, lock));
  449. }
  450. static inline
  451. int threadobj_cond_signal(pthread_cond_t *cond)
  452. {
  453. return __RT(pthread_cond_signal(cond));
  454. }
  455. static inline
  456. int threadobj_cond_broadcast(pthread_cond_t *cond)
  457. {
  458. return __RT(pthread_cond_broadcast(cond));
  459. }
  460. #endif /* !CONFIG_XENO_WORKAROUND_CONDVAR_PI */
  461. #endif /* _COPPERPLATE_THREADOBJ_H */