ChibiOS/RT  6.1.4
chthreads.c
Go to the documentation of this file.
1 /*
2  ChibiOS - Copyright (C) 2006,2007,2008,2009,2010,2011,2012,2013,2014,
3  2015,2016,2017,2018,2019,2020,2021 Giovanni Di Sirio.
4 
5  This file is part of ChibiOS.
6 
7  ChibiOS is free software; you can redistribute it and/or modify
8  it under the terms of the GNU General Public License as published by
9  the Free Software Foundation version 3 of the License.
10 
11  ChibiOS is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 /**
21  * @file rt/src/chthreads.c
22  * @brief Threads code.
23  *
24  * @addtogroup threads
25  * @details Threads related APIs and services.
26  * <h2>Operation mode</h2>
27  * A thread is an abstraction of an independent instructions flow.
28  * In ChibiOS/RT a thread is represented by a "C" function owning
29  * a processor context, state informations and a dedicated stack
30  * area. In this scenario static variables are shared among all
31  * threads while automatic variables are local to the thread.<br>
32  * Operations defined for threads:
33  * - <b>Create</b>, a thread is started on the specified thread
34  * function. This operation is available in multiple variants,
35  * both static and dynamic.
36  * - <b>Exit</b>, a thread terminates by returning from its top
37  * level function or invoking a specific API, the thread can
38  * return a value that can be retrieved by other threads.
39  * - <b>Wait</b>, a thread waits for the termination of another
40  * thread and retrieves its return value.
41  * - <b>Resume</b>, a thread created in suspended state is started.
42  * - <b>Sleep</b>, the execution of a thread is suspended for the
43  * specified amount of time or the specified future absolute time
44  * is reached.
45  * - <b>SetPriority</b>, a thread changes its own priority level.
46  * - <b>Yield</b>, a thread voluntarily renounces to its time slot.
47  * .
48  * @{
49  */
50 
51 #include "ch.h"
52 
53 /*===========================================================================*/
54 /* Module local definitions. */
55 /*===========================================================================*/
56 
57 /*===========================================================================*/
58 /* Module exported variables. */
59 /*===========================================================================*/
60 
61 /*===========================================================================*/
62 /* Module local types. */
63 /*===========================================================================*/
64 
65 /*===========================================================================*/
66 /* Module local variables. */
67 /*===========================================================================*/
68 
69 /*===========================================================================*/
70 /* Module local functions. */
71 /*===========================================================================*/
72 
73 /*===========================================================================*/
74 /* Module exported functions. */
75 /*===========================================================================*/
76 
77 /**
78  * @brief Initializes a thread structure.
79  * @note This is an internal functions, do not use it in application code.
80  *
81  * @param[in] tp pointer to the thread
82  * @param[in] name thread name
83  * @param[in] prio the priority level for the new thread
84  * @return The same thread pointer passed as parameter.
85  *
86  * @notapi
87  */
88 thread_t *_thread_init(thread_t *tp, const char *name, tprio_t prio) {
89 
90  tp->hdr.pqueue.prio = prio;
91  tp->state = CH_STATE_WTSTART;
93 #if CH_CFG_TIME_QUANTUM > 0
94  tp->ticks = (tslices_t)CH_CFG_TIME_QUANTUM;
95 #endif
96 #if CH_CFG_USE_MUTEXES == TRUE
97  tp->realprio = prio;
98  tp->mtxlist = NULL;
99 #endif
100 #if CH_CFG_USE_EVENTS == TRUE
101  tp->epending = (eventmask_t)0;
102 #endif
103 #if CH_DBG_THREADS_PROFILING == TRUE
104  tp->time = (systime_t)0;
105 #endif
106 #if CH_CFG_USE_REGISTRY == TRUE
107  tp->refs = (trefs_t)1;
108  tp->name = name;
109  REG_INSERT(tp);
110 #else
111  (void)name;
112 #endif
113 #if CH_CFG_USE_WAITEXIT == TRUE
114  ch_list_init(&tp->waiting);
115 #endif
116 #if CH_CFG_USE_MESSAGES == TRUE
117  ch_queue_init(&tp->msgqueue);
118 #endif
119 #if CH_DBG_STATISTICS == TRUE
120  chTMObjectInit(&tp->stats);
121 #endif
123  return tp;
124 }
125 
126 #if (CH_DBG_FILL_THREADS == TRUE) || defined(__DOXYGEN__)
127 /**
128  * @brief Memory fill utility.
129  *
130  * @param[in] startp first address to fill
131  * @param[in] endp last address to fill +1
132  * @param[in] v filler value
133  *
134  * @notapi
135  */
136 void _thread_memfill(uint8_t *startp, uint8_t *endp, uint8_t v) {
137 
138  while (startp < endp) {
139  *startp++ = v;
140  }
141 }
142 #endif /* CH_DBG_FILL_THREADS */
143 
144 /**
145  * @brief Creates a new thread into a static memory area.
146  * @details The new thread is initialized but not inserted in the ready list,
147  * the initial state is @p CH_STATE_WTSTART.
148  * @post The created thread has a reference counter set to one, it is
149  * caller responsibility to call @p chThdRelease() or @p chthdWait()
150  * in order to release the reference. The thread persists in the
151  * registry until its reference counter reaches zero.
152  * @post The initialized thread can be subsequently started by invoking
153  * @p chThdStart(), @p chThdStartI() or @p chSchWakeupS()
154  * depending on the execution context.
155  * @note A thread can terminate by calling @p chThdExit() or by simply
156  * returning from its main function.
157  * @note Threads created using this function do not obey to the
158  * @p CH_DBG_FILL_THREADS debug option because it would keep
159  * the kernel locked for too much time.
160  *
161  * @param[out] tdp pointer to the thread descriptor
162  * @return The pointer to the @p thread_t structure allocated for
163  * the thread into the working space area.
164  *
165  * @iclass
166  */
168  thread_t *tp;
169 
171  chDbgCheck(tdp != NULL);
172  chDbgCheck(MEM_IS_ALIGNED(tdp->wbase, PORT_WORKING_AREA_ALIGN) &&
173  MEM_IS_ALIGNED(tdp->wend, PORT_STACK_ALIGN) &&
174  (tdp->wend > tdp->wbase) &&
175  (((size_t)tdp->wend - (size_t)tdp->wbase) >= THD_WORKING_AREA_SIZE(0)));
176  chDbgCheck((tdp->prio <= HIGHPRIO) && (tdp->funcp != NULL));
177 
178  /* The thread structure is laid out in the upper part of the thread
179  workspace. The thread position structure is aligned to the required
180  stack alignment because it represents the stack top.*/
181  tp = (thread_t *)((uint8_t *)tdp->wend -
182  MEM_ALIGN_NEXT(sizeof (thread_t), PORT_STACK_ALIGN));
183 
184 #if (CH_DBG_ENABLE_STACK_CHECK == TRUE) || (CH_CFG_USE_DYNAMIC == TRUE)
185  /* Stack boundary.*/
186  tp->wabase = tdp->wbase;
187 #endif
188 
189  /* Setting up the port-dependent part of the working area.*/
190  PORT_SETUP_CONTEXT(tp, tdp->wbase, tp, tdp->funcp, tdp->arg);
191 
192  /* The driver object is initialized but not started.*/
193  return _thread_init(tp, tdp->name, tdp->prio);
194 }
195 
196 /**
197  * @brief Creates a new thread into a static memory area.
198  * @details The new thread is initialized but not inserted in the ready list,
199  * the initial state is @p CH_STATE_WTSTART.
200  * @post The created thread has a reference counter set to one, it is
201  * caller responsibility to call @p chThdRelease() or @p chthdWait()
202  * in order to release the reference. The thread persists in the
203  * registry until its reference counter reaches zero.
204  * @post The initialized thread can be subsequently started by invoking
205  * @p chThdStart(), @p chThdStartI() or @p chSchWakeupS()
206  * depending on the execution context.
207  * @note A thread can terminate by calling @p chThdExit() or by simply
208  * returning from its main function.
209  *
210  * @param[out] tdp pointer to the thread descriptor
211  * @return The pointer to the @p thread_t structure allocated for
212  * the thread into the working space area.
213  *
214  * @api
215  */
217  thread_t *tp;
218 
219 #if CH_CFG_USE_REGISTRY == TRUE
221  "working area in use");
222 #endif
223 
224 #if CH_DBG_FILL_THREADS == TRUE
225  _thread_memfill((uint8_t *)tdp->wbase,
226  (uint8_t *)tdp->wend,
228 #endif
229 
230  chSysLock();
231  tp = chThdCreateSuspendedI(tdp);
232  chSysUnlock();
233 
234  return tp;
235 }
236 
237 /**
238  * @brief Creates a new thread into a static memory area.
239  * @details The new thread is initialized and make ready to execute.
240  * @post The created thread has a reference counter set to one, it is
241  * caller responsibility to call @p chThdRelease() or @p chthdWait()
242  * in order to release the reference. The thread persists in the
243  * registry until its reference counter reaches zero.
244  * @post The initialized thread can be subsequently started by invoking
245  * @p chThdStart(), @p chThdStartI() or @p chSchWakeupS()
246  * depending on the execution context.
247  * @note A thread can terminate by calling @p chThdExit() or by simply
248  * returning from its main function.
249  * @note Threads created using this function do not obey to the
250  * @p CH_DBG_FILL_THREADS debug option because it would keep
251  * the kernel locked for too much time.
252  *
253  * @param[out] tdp pointer to the thread descriptor
254  * @return The pointer to the @p thread_t structure allocated for
255  * the thread into the working space area.
256  *
257  * @iclass
258  */
260 
261  return chSchReadyI(chThdCreateSuspendedI(tdp));
262 }
263 
264 /**
265  * @brief Creates a new thread into a static memory area.
266  * @details The new thread is initialized and make ready to execute.
267  * @post The created thread has a reference counter set to one, it is
268  * caller responsibility to call @p chThdRelease() or @p chthdWait()
269  * in order to release the reference. The thread persists in the
270  * registry until its reference counter reaches zero.
271  * @note A thread can terminate by calling @p chThdExit() or by simply
272  * returning from its main function.
273  *
274  * @param[out] tdp pointer to the thread descriptor
275  * @return The pointer to the @p thread_t structure allocated for
276  * the thread into the working space area.
277  *
278  * @iclass
279  */
281  thread_t *tp;
282 
283 #if (CH_CFG_USE_REGISTRY == TRUE) && \
284  ((CH_DBG_ENABLE_STACK_CHECK == TRUE) || (CH_CFG_USE_DYNAMIC == TRUE))
286  "working area in use");
287 #endif
288 
289 #if CH_DBG_FILL_THREADS == TRUE
290  _thread_memfill((uint8_t *)tdp->wbase,
291  (uint8_t *)tdp->wend,
293 #endif
294 
295  chSysLock();
296  tp = chThdCreateSuspendedI(tdp);
297  chSchWakeupS(tp, MSG_OK);
298  chSysUnlock();
299 
300  return tp;
301 }
302 
303 /**
304  * @brief Creates a new thread into a static memory area.
305  * @post The created thread has a reference counter set to one, it is
306  * caller responsibility to call @p chThdRelease() or @p chThdWait()
307  * in order to release the reference. The thread persists in the
308  * registry until its reference counter reaches zero.
309  * @note A thread can terminate by calling @p chThdExit() or by simply
310  * returning from its main function.
311  *
312  * @param[out] wsp pointer to a working area dedicated to the thread stack
313  * @param[in] size size of the working area
314  * @param[in] prio the priority level for the new thread
315  * @param[in] pf the thread function
316  * @param[in] arg an argument passed to the thread function. It can be
317  * @p NULL.
318  * @return The pointer to the @p thread_t structure allocated for
319  * the thread into the working space area.
320  *
321  * @api
322  */
323 thread_t *chThdCreateStatic(void *wsp, size_t size,
324  tprio_t prio, tfunc_t pf, void *arg) {
325  thread_t *tp;
326 
327  chDbgCheck((wsp != NULL) &&
328  MEM_IS_ALIGNED(wsp, PORT_WORKING_AREA_ALIGN) &&
329  (size >= THD_WORKING_AREA_SIZE(0)) &&
330  MEM_IS_ALIGNED(size, PORT_STACK_ALIGN) &&
331  (prio <= HIGHPRIO) && (pf != NULL));
332 
333 #if (CH_CFG_USE_REGISTRY == TRUE) && \
334  ((CH_DBG_ENABLE_STACK_CHECK == TRUE) || (CH_CFG_USE_DYNAMIC == TRUE))
336  "working area in use");
337 #endif
338 
339 #if CH_DBG_FILL_THREADS == TRUE
340  _thread_memfill((uint8_t *)wsp,
341  (uint8_t *)wsp + size,
343 #endif
344 
345  chSysLock();
346 
347  /* The thread structure is laid out in the upper part of the thread
348  workspace. The thread position structure is aligned to the required
349  stack alignment because it represents the stack top.*/
350  tp = (thread_t *)((uint8_t *)wsp + size -
351  MEM_ALIGN_NEXT(sizeof (thread_t), PORT_STACK_ALIGN));
352 
353 #if (CH_DBG_ENABLE_STACK_CHECK == TRUE) || (CH_CFG_USE_DYNAMIC == TRUE)
354  /* Stack boundary.*/
355  tp->wabase = (stkalign_t *)wsp;
356 #endif
357 
358  /* Setting up the port-dependent part of the working area.*/
359  PORT_SETUP_CONTEXT(tp, wsp, tp, pf, arg);
360 
361  tp = _thread_init(tp, "noname", prio);
362 
363  /* Starting the thread immediately.*/
364  chSchWakeupS(tp, MSG_OK);
365  chSysUnlock();
366 
367  return tp;
368 }
369 
370 /**
371  * @brief Resumes a thread created with @p chThdCreateI().
372  *
373  * @param[in] tp pointer to the thread
374  * @return The pointer to the @p thread_t structure allocated for
375  * the thread into the working space area.
376  *
377  * @api
378  */
380 
381  chSysLock();
382  chDbgAssert(tp->state == CH_STATE_WTSTART, "wrong state");
383  chSchWakeupS(tp, MSG_OK);
384  chSysUnlock();
385 
386  return tp;
387 }
388 
389 #if (CH_CFG_USE_REGISTRY == TRUE) || defined(__DOXYGEN__)
390 /**
391  * @brief Adds a reference to a thread object.
392  * @pre The configuration option @p CH_CFG_USE_REGISTRY must be enabled in
393  * order to use this function.
394  *
395  * @param[in] tp pointer to the thread
396  * @return The same thread pointer passed as parameter
397  * representing the new reference.
398  *
399  * @api
400  */
402 
403  chSysLock();
404  chDbgAssert(tp->refs < (trefs_t)255, "too many references");
405  tp->refs++;
406  chSysUnlock();
407 
408  return tp;
409 }
410 
411 /**
412  * @brief Releases a reference to a thread object.
413  * @details If the references counter reaches zero <b>and</b> the thread
414  * is in the @p CH_STATE_FINAL state then the thread's memory is
415  * returned to the proper allocator and the thread is removed
416  * from the registry.<br>
417  * Threads whose counter reaches zero and are still active become
418  * "detached" and will be removed from registry on termination.
419  * @pre The configuration option @p CH_CFG_USE_REGISTRY must be enabled in
420  * order to use this function.
421  * @note Static threads are not affected.
422  *
423  * @param[in] tp pointer to the thread
424  *
425  * @api
426  */
428 
429  chSysLock();
430  chDbgAssert(tp->refs > (trefs_t)0, "not referenced");
431  tp->refs--;
432 
433  /* If the references counter reaches zero and the thread is in its
434  terminated state then the memory can be returned to the proper
435  allocator.*/
436  if ((tp->refs == (trefs_t)0) && (tp->state == CH_STATE_FINAL)) {
437  REG_REMOVE(tp);
438  chSysUnlock();
439 
440 #if CH_CFG_USE_DYNAMIC == TRUE
441  switch (tp->flags & CH_FLAG_MODE_MASK) {
442 #if CH_CFG_USE_HEAP == TRUE
443  case CH_FLAG_MODE_HEAP:
445  break;
446 #endif
447 #if CH_CFG_USE_MEMPOOLS == TRUE
448  case CH_FLAG_MODE_MPOOL:
450  break;
451 #endif
452  default:
453  /* Nothing else to do for static threads.*/
454  break;
455  }
456 #endif /* CH_CFG_USE_DYNAMIC == TRUE */
457  return;
458  }
459  chSysUnlock();
460 }
461 #endif /* CH_CFG_USE_REGISTRY == TRUE */
462 
463 /**
464  * @brief Terminates the current thread.
465  * @details The thread goes in the @p CH_STATE_FINAL state holding the
466  * specified exit status code, other threads can retrieve the
467  * exit status code by invoking the function @p chThdWait().
468  * @post Eventual code after this function will never be executed,
469  * this function never returns. The compiler has no way to
470  * know this so do not assume that the compiler would remove
471  * the dead code.
472  *
473  * @param[in] msg thread exit code
474  *
475  * @api
476  */
477 void chThdExit(msg_t msg) {
478 
479  chSysLock();
480  chThdExitS(msg);
481  /* The thread never returns here.*/
482 }
483 
484 /**
485  * @brief Terminates the current thread.
486  * @details The thread goes in the @p CH_STATE_FINAL state holding the
487  * specified exit status code, other threads can retrieve the
488  * exit status code by invoking the function @p chThdWait().
489  * @post Exiting a non-static thread that does not have references
490  * (detached) causes the thread to remain in the registry.
491  * It can only be removed by performing a registry scan operation.
492  * @post Eventual code after this function will never be executed,
493  * this function never returns. The compiler has no way to
494  * know this so do not assume that the compiler would remove
495  * the dead code.
496  *
497  * @param[in] msg thread exit code
498  *
499  * @sclass
500  */
501 void chThdExitS(msg_t msg) {
502  thread_t *tp = currp;
503 
504  /* Storing exit message.*/
505  tp->u.exitcode = msg;
506 
507  /* Exit handler hook.*/
509 
510 #if CH_CFG_USE_WAITEXIT == TRUE
511  /* Waking up any waiting thread.*/
512  while (ch_list_notempty(&tp->waiting)) {
513  (void) chSchReadyI((thread_t *)ch_list_pop(&tp->waiting));
514  }
515 #endif
516 
517 #if CH_CFG_USE_REGISTRY == TRUE
518  /* Static threads with no references are immediately removed from the
519  registry because there is no memory to recover.*/
520 #if CH_CFG_USE_DYNAMIC == TRUE
521  if ((tp->refs == (trefs_t)0) &&
523  REG_REMOVE(tp);
524  }
525 #else
526  if (tp->refs == (trefs_t)0) {
527  REG_REMOVE(tp);
528  }
529 #endif
530 #endif
531 
532  /* Going into final state.*/
534 
535  /* The thread never returns here.*/
536  chDbgAssert(false, "zombies apocalypse");
537 }
538 
539 #if (CH_CFG_USE_WAITEXIT == TRUE) || defined(__DOXYGEN__)
540 /**
541  * @brief Blocks the execution of the invoking thread until the specified
542  * thread terminates then the exit code is returned.
543  * @details This function waits for the specified thread to terminate then
544  * decrements its reference counter, if the counter reaches zero then
545  * the thread working area is returned to the proper allocator and
546  * the thread is removed from registry.
547  * @pre The configuration option @p CH_CFG_USE_WAITEXIT must be enabled in
548  * order to use this function.
549  * @post Enabling @p chThdWait() requires 2-4 (depending on the
550  * architecture) extra bytes in the @p thread_t structure.
551  * @note If @p CH_CFG_USE_DYNAMIC is not specified this function just waits
552  * for the thread termination, no memory allocators are involved.
553  *
554  * @param[in] tp pointer to the thread
555  * @return The exit code from the terminated thread.
556  *
557  * @api
558  */
559 msg_t chThdWait(thread_t *tp) {
560  msg_t msg;
561 
562  chDbgCheck(tp != NULL);
563 
564  chSysLock();
565  chDbgAssert(tp != currp, "waiting self");
566 #if CH_CFG_USE_REGISTRY == TRUE
567  chDbgAssert(tp->refs > (trefs_t)0, "no references");
568 #endif
569 
570  if (tp->state != CH_STATE_FINAL) {
571  ch_list_push(&currp->hdr.list, &tp->waiting);
573  }
574  msg = tp->u.exitcode;
575  chSysUnlock();
576 
577 #if CH_CFG_USE_REGISTRY == TRUE
578  /* Releasing a reference to the thread.*/
579  chThdRelease(tp);
580 #endif
581 
582  return msg;
583 }
584 #endif /* CH_CFG_USE_WAITEXIT */
585 
586 /**
587  * @brief Changes the running thread priority level then reschedules if
588  * necessary.
589  * @note The function returns the real thread priority regardless of the
590  * current priority that could be higher than the real priority
591  * because the priority inheritance mechanism.
592  *
593  * @param[in] newprio the new priority level of the running thread
594  * @return The old priority level.
595  *
596  * @api
597  */
598 tprio_t chThdSetPriority(tprio_t newprio) {
599  tprio_t oldprio;
600 
601  chDbgCheck(newprio <= HIGHPRIO);
602 
603  chSysLock();
604 #if CH_CFG_USE_MUTEXES == TRUE
605  oldprio = currp->realprio;
606  if ((currp->hdr.pqueue.prio == currp->realprio) ||
607  (newprio > currp->hdr.pqueue.prio)) {
608  currp->hdr.pqueue.prio = newprio;
609  }
610  currp->realprio = newprio;
611 #else
612  oldprio = currp->hdr.pqueue.prio;
613  currp->hdr.pqueue.prio = newprio;
614 #endif
616  chSysUnlock();
617 
618  return oldprio;
619 }
620 
621 /**
622  * @brief Requests a thread termination.
623  * @pre The target thread must be written to invoke periodically
624  * @p chThdShouldTerminate() and terminate cleanly if it returns
625  * @p true.
626  * @post The specified thread will terminate after detecting the termination
627  * condition.
628  *
629  * @param[in] tp pointer to the thread
630  *
631  * @api
632  */
634 
635  chSysLock();
636  tp->flags |= CH_FLAG_TERMINATE;
637  chSysUnlock();
638 }
639 
640 /**
641  * @brief Suspends the invoking thread for the specified time.
642  *
643  * @param[in] time the delay in system ticks, the special values are
644  * handled as follow:
645  * - @a TIME_INFINITE the thread enters an infinite sleep
646  * state.
647  * - @a TIME_IMMEDIATE this value is not allowed.
648  * .
649  *
650  * @api
651  */
653 
654  chSysLock();
655  chThdSleepS(time);
656  chSysUnlock();
657 }
658 
659 /**
660  * @brief Suspends the invoking thread until the system time arrives to the
661  * specified value.
662  * @note The function has no concept of "past", all specifiable times
663  * are in the future, this means that if you call this function
664  * exceeding your calculated intervals then the function will
665  * return in a far future time, not immediately.
666  * @see chThdSleepUntilWindowed()
667  *
668  * @param[in] time absolute system time
669  *
670  * @api
671  */
673  sysinterval_t interval;
674 
675  chSysLock();
676  interval = chTimeDiffX(chVTGetSystemTimeX(), time);
677  if (interval > (sysinterval_t)0) {
678  chThdSleepS(interval);
679  }
680  chSysUnlock();
681 }
682 
683 /**
684  * @brief Suspends the invoking thread until the system time arrives to the
685  * specified value.
686  * @note The system time is assumed to be between @p prev and @p next
687  * else the call is assumed to have been called outside the
688  * allowed time interval, in this case no sleep is performed.
689  * @see chThdSleepUntil()
690  *
691  * @param[in] prev absolute system time of the previous deadline
692  * @param[in] next absolute system time of the next deadline
693  * @return the @p next parameter
694  *
695  * @api
696  */
698  systime_t time;
699 
700  chSysLock();
701  time = chVTGetSystemTimeX();
702  if (chTimeIsInRangeX(time, prev, next)) {
703  chThdSleepS(chTimeDiffX(time, next));
704  }
705  chSysUnlock();
706 
707  return next;
708 }
709 
710 /**
711  * @brief Yields the time slot.
712  * @details Yields the CPU control to the next thread in the ready list with
713  * equal priority, if any.
714  *
715  * @api
716  */
717 void chThdYield(void) {
718 
719  chSysLock();
720  chSchDoYieldS();
721  chSysUnlock();
722 }
723 
724 /**
725  * @brief Sends the current thread sleeping and sets a reference variable.
726  * @note This function must reschedule, it can only be called from thread
727  * context.
728  *
729  * @param[in] trp a pointer to a thread reference object
730  * @return The wake up message.
731  *
732  * @sclass
733  */
735  thread_t *tp = chThdGetSelfX();
736 
737  chDbgAssert(*trp == NULL, "not NULL");
738 
739  *trp = tp;
740  tp->u.wttrp = trp;
742 
743  return chThdGetSelfX()->u.rdymsg;
744 }
745 
746 /**
747  * @brief Sends the current thread sleeping and sets a reference variable.
748  * @note This function must reschedule, it can only be called from thread
749  * context.
750  *
751  * @param[in] trp a pointer to a thread reference object
752  * @param[in] timeout the timeout in system ticks, the special values are
753  * handled as follow:
754  * - @a TIME_INFINITE the thread enters an infinite sleep
755  * state.
756  * - @a TIME_IMMEDIATE the thread is not enqueued and
757  * the function returns @p MSG_TIMEOUT as if a timeout
758  * occurred.
759  * .
760  * @return The wake up message.
761  * @retval MSG_TIMEOUT if the operation timed out.
762  *
763  * @sclass
764  */
766  thread_t *tp = chThdGetSelfX();
767 
768  chDbgAssert(*trp == NULL, "not NULL");
769 
770  if (TIME_IMMEDIATE == timeout) {
771  return MSG_TIMEOUT;
772  }
773 
774  *trp = tp;
775  tp->u.wttrp = trp;
776 
777  return chSchGoSleepTimeoutS(CH_STATE_SUSPENDED, timeout);
778 }
779 
780 /**
781  * @brief Wakes up a thread waiting on a thread reference object.
782  * @note This function must not reschedule because it can be called from
783  * ISR context.
784  *
785  * @param[in] trp a pointer to a thread reference object
786  * @param[in] msg the message code
787  *
788  * @iclass
789  */
790 void chThdResumeI(thread_reference_t *trp, msg_t msg) {
791 
792  if (*trp != NULL) {
793  thread_t *tp = *trp;
794 
795  chDbgAssert(tp->state == CH_STATE_SUSPENDED, "not CH_STATE_SUSPENDED");
796 
797  *trp = NULL;
798  tp->u.rdymsg = msg;
799  (void) chSchReadyI(tp);
800  }
801 }
802 
803 /**
804  * @brief Wakes up a thread waiting on a thread reference object.
805  * @note This function must reschedule, it can only be called from thread
806  * context.
807  *
808  * @param[in] trp a pointer to a thread reference object
809  * @param[in] msg the message code
810  *
811  * @iclass
812  */
813 void chThdResumeS(thread_reference_t *trp, msg_t msg) {
814 
815  if (*trp != NULL) {
816  thread_t *tp = *trp;
817 
818  chDbgAssert(tp->state == CH_STATE_SUSPENDED, "not CH_STATE_SUSPENDED");
819 
820  *trp = NULL;
821  chSchWakeupS(tp, msg);
822  }
823 }
824 
825 /**
826  * @brief Wakes up a thread waiting on a thread reference object.
827  * @note This function must reschedule, it can only be called from thread
828  * context.
829  *
830  * @param[in] trp a pointer to a thread reference object
831  * @param[in] msg the message code
832  *
833  * @api
834  */
835 void chThdResume(thread_reference_t *trp, msg_t msg) {
836 
837  chSysLock();
838  chThdResumeS(trp, msg);
839  chSysUnlock();
840 }
841 
842 /**
843  * @brief Enqueues the caller thread on a threads queue object.
844  * @details The caller thread is enqueued and put to sleep until it is
845  * dequeued or the specified timeouts expires.
846  *
847  * @param[in] tqp pointer to the threads queue object
848  * @param[in] timeout the timeout in system ticks, the special values are
849  * handled as follow:
850  * - @a TIME_INFINITE the thread enters an infinite sleep
851  * state.
852  * - @a TIME_IMMEDIATE the thread is not enqueued and
853  * the function returns @p MSG_TIMEOUT as if a timeout
854  * occurred.
855  * .
856  * @return The message from @p osalQueueWakeupOneI() or
857  * @p osalQueueWakeupAllI() functions.
858  * @retval MSG_TIMEOUT if the thread has not been dequeued within the
859  * specified timeout or if the function has been
860  * invoked with @p TIME_IMMEDIATE as timeout
861  * specification.
862  *
863  * @sclass
864  */
866 
867  if (TIME_IMMEDIATE == timeout) {
868  return MSG_TIMEOUT;
869  }
870 
871  ch_queue_insert(&currp->hdr.queue, &tqp->queue);
872 
873  return chSchGoSleepTimeoutS(CH_STATE_QUEUED, timeout);
874 }
875 
876 /**
877  * @brief Dequeues and wakes up one thread from the threads queue object,
878  * if any.
879  *
880  * @param[in] tqp pointer to the threads queue object
881  * @param[in] msg the message code
882  *
883  * @iclass
884  */
885 void chThdDequeueNextI(threads_queue_t *tqp, msg_t msg) {
886 
887  if (ch_queue_notempty(&tqp->queue)) {
888  chThdDoDequeueNextI(tqp, msg);
889  }
890 }
891 
892 /**
893  * @brief Dequeues and wakes up all threads from the threads queue object.
894  *
895  * @param[in] tqp pointer to the threads queue object
896  * @param[in] msg the message code
897  *
898  * @iclass
899  */
900 void chThdDequeueAllI(threads_queue_t *tqp, msg_t msg) {
901 
902  while (ch_queue_notempty(&tqp->queue)) {
903  chThdDoDequeueNextI(tqp, msg);
904  }
905 }
906 
907 /** @} */
chSchDoYieldS
static void chSchDoYieldS(void)
Yields the time slot.
Definition: chschd.h:560
ch_thread::wttrp
thread_reference_t * wttrp
Pointer to a generic thread reference object.
Definition: chschd.h:222
chThdCreateSuspended
thread_t * chThdCreateSuspended(const thread_descriptor_t *tdp)
Creates a new thread into a static memory area.
Definition: chthreads.c:216
chThdSuspendTimeoutS
msg_t chThdSuspendTimeoutS(thread_reference_t *trp, sysinterval_t timeout)
Sends the current thread sleeping and sets a reference variable.
Definition: chthreads.c:765
chSysLock
static void chSysLock(void)
Enters the kernel lock state.
Definition: chsys.h:355
chSchReadyI
thread_t * chSchReadyI(thread_t *tp)
Inserts a thread in the Ready List placing it behind its peers.
Definition: chschd.c:153
ch_thread::realprio
tprio_t realprio
Thread's own, non-inherited, priority.
Definition: chschd.h:283
ch_thread::epending
eventmask_t epending
Pending events mask.
Definition: chschd.h:272
CH_FLAG_MODE_MASK
#define CH_FLAG_MODE_MASK
Thread memory mode mask.
Definition: chschd.h:98
ch_thread::pqueue
ch_priority_queue_t pqueue
Threads ordered queues element.
Definition: chschd.h:138
THD_WORKING_AREA_SIZE
#define THD_WORKING_AREA_SIZE(n)
Calculates the total Working Area size.
Definition: chthreads.h:124
chPoolFree
void chPoolFree(memory_pool_t *mp, void *objp)
Releases an object into a memory pool.
Definition: chmempools.c:207
CH_STATE_WTSTART
#define CH_STATE_WTSTART
Just created.
Definition: chschd.h:65
currp
#define currp
Current thread pointer access macro.
Definition: chschd.h:462
ch_thread::rdymsg
msg_t rdymsg
Thread wakeup code.
Definition: chschd.h:201
CH_CFG_TIME_QUANTUM
#define CH_CFG_TIME_QUANTUM
Round robin interval.
Definition: chconf.h:108
chThdAddRef
thread_t * chThdAddRef(thread_t *tp)
Adds a reference to a thread object.
Definition: chthreads.c:401
chVTGetSystemTimeX
static systime_t chVTGetSystemTimeX(void)
Current system time.
Definition: chvt.h:116
ch_threads_queue
Structure representing a threads queue.
Definition: chschd.h:124
chThdCreateStatic
thread_t * chThdCreateStatic(void *wsp, size_t size, tprio_t prio, tfunc_t pf, void *arg)
Creates a new thread into a static memory area.
Definition: chthreads.c:323
systime_t
uint64_t systime_t
Type of system time.
Definition: chtime.h:107
chDbgAssert
#define chDbgAssert(c, r)
Condition assertion.
Definition: chdebug.h:127
CH_STATE_SUSPENDED
#define CH_STATE_SUSPENDED
Suspended state.
Definition: chschd.h:66
thread_descriptor_t::wend
stkalign_t * wend
End of the working area.
Definition: chthreads.h:69
chThdCreateSuspendedI
thread_t * chThdCreateSuspendedI(const thread_descriptor_t *tdp)
Creates a new thread into a static memory area.
Definition: chthreads.c:167
tfunc_t
void(* tfunc_t)(void *p)
Thread function.
Definition: chthreads.h:52
ch_thread::mtxlist
struct ch_mutex * mtxlist
List of the mutexes owned by this thread.
Definition: chschd.h:279
CH_DBG_STACK_FILL_VALUE
#define CH_DBG_STACK_FILL_VALUE
Fill value for thread stack area in debug mode.
Definition: chdebug.h:47
chHeapFree
void chHeapFree(void *p)
Frees a previously allocated memory block.
Definition: chmemheaps.c:293
chThdResumeS
void chThdResumeS(thread_reference_t *trp, msg_t msg)
Wakes up a thread waiting on a thread reference object.
Definition: chthreads.c:813
chTimeDiffX
static sysinterval_t chTimeDiffX(systime_t start, systime_t end)
Subtracts two system times returning an interval.
Definition: chtime.h:459
CH_CFG_THREAD_EXIT_HOOK
#define CH_CFG_THREAD_EXIT_HOOK(tp)
Threads finalization hook.
Definition: chconf.h:667
chThdCreateI
thread_t * chThdCreateI(const thread_descriptor_t *tdp)
Creates a new thread into a static memory area.
Definition: chthreads.c:259
ch_queue_notempty
static bool ch_queue_notempty(const ch_queue_t *qp)
Evaluates to true if the specified queue is not empty.
Definition: chlists.h:234
chThdGetWorkingAreaX
static stkalign_t * chThdGetWorkingAreaX(thread_t *tp)
Returns the working area base of the specified thread.
Definition: chthreads.h:320
CH_CFG_THREAD_INIT_HOOK
#define CH_CFG_THREAD_INIT_HOOK(tp)
Threads initialization hook.
Definition: chconf.h:659
chSchGoSleepTimeoutS
msg_t chSchGoSleepTimeoutS(tstate_t newstate, sysinterval_t timeout)
Puts the current thread to sleep into the specified state with timeout specification.
Definition: chschd.c:258
CH_FLAG_MODE_MPOOL
#define CH_FLAG_MODE_MPOOL
Thread allocated from a Memory Pool.
Definition: chschd.h:103
thread_descriptor_t::wbase
stkalign_t * wbase
Pointer to the working area base.
Definition: chthreads.h:65
chThdDequeueAllI
void chThdDequeueAllI(threads_queue_t *tqp, msg_t msg)
Dequeues and wakes up all threads from the threads queue object.
Definition: chthreads.c:900
REG_INSERT
#define REG_INSERT(tp)
Adds a thread to the registry list.
Definition: chregistry.h:94
chThdTerminate
void chThdTerminate(thread_t *tp)
Requests a thread termination.
Definition: chthreads.c:633
chThdEnqueueTimeoutS
msg_t chThdEnqueueTimeoutS(threads_queue_t *tqp, sysinterval_t timeout)
Enqueues the caller thread on a threads queue object.
Definition: chthreads.c:865
chDbgCheck
#define chDbgCheck(c)
Function parameters check.
Definition: chdebug.h:101
ch_thread::refs
trefs_t refs
References to this thread.
Definition: chschd.h:174
TIME_IMMEDIATE
#define TIME_IMMEDIATE
Zero interval specification for some functions with a timeout specification.
Definition: chtime.h:47
ch_list_push
static void ch_list_push(ch_list_t *p, ch_list_t *lp)
Pushes an element on top of a stack list.
Definition: chlists.h:177
ch_thread::name
const char * name
Thread name or NULL.
Definition: chschd.h:151
MEM_IS_ALIGNED
#define MEM_IS_ALIGNED(p, a)
Returns whatever a pointer or memory size is aligned.
Definition: chalign.h:91
thread_descriptor_t::funcp
tfunc_t funcp
Thread function pointer.
Definition: chthreads.h:77
chThdResumeI
void chThdResumeI(thread_reference_t *trp, msg_t msg)
Wakes up a thread waiting on a thread reference object.
Definition: chthreads.c:790
ch_list_notempty
static bool ch_list_notempty(ch_list_t *lp)
Evaluates to true if the specified list is not empty.
Definition: chlists.h:164
HIGHPRIO
#define HIGHPRIO
Highest priority.
Definition: chschd.h:55
ch_thread
Structure representing a thread.
Definition: chschd.h:134
_thread_memfill
void _thread_memfill(uint8_t *startp, uint8_t *endp, uint8_t v)
Memory fill utility.
Definition: chthreads.c:136
chSchGoSleepS
void chSchGoSleepS(tstate_t newstate)
Puts the current thread to sleep into the specified state.
Definition: chschd.c:210
ch_thread::wabase
stkalign_t * wabase
Working area base address.
Definition: chschd.h:160
chRegFindThreadByWorkingArea
thread_t * chRegFindThreadByWorkingArea(stkalign_t *wa)
Confirms that a working area is being used by some active thread.
Definition: chregistry.c:249
ch_thread::ticks
tslices_t ticks
Number of ticks remaining to this thread.
Definition: chschd.h:180
chThdWait
msg_t chThdWait(thread_t *tp)
Blocks the execution of the invoking thread until the specified thread terminates then the exit code ...
Definition: chthreads.c:559
CH_FLAG_MODE_HEAP
#define CH_FLAG_MODE_HEAP
Thread allocated from a Memory Heap.
Definition: chschd.h:101
CH_STATE_FINAL
#define CH_STATE_FINAL
Thread terminated.
Definition: chschd.h:81
ch_thread::msgqueue
ch_queue_t msgqueue
Messages queue.
Definition: chschd.h:266
ch_thread::u
union ch_thread::@1 u
State-specific fields.
thread_descriptor_t
Type of a thread descriptor.
Definition: chthreads.h:57
chThdSetPriority
tprio_t chThdSetPriority(tprio_t newprio)
Changes the running thread priority level then reschedules if necessary.
Definition: chthreads.c:598
MEM_ALIGN_NEXT
#define MEM_ALIGN_NEXT(p, a)
Aligns to the next aligned memory address.
Definition: chalign.h:80
thread_descriptor_t::arg
void * arg
Thread argument.
Definition: chthreads.h:81
chThdSuspendS
msg_t chThdSuspendS(thread_reference_t *trp)
Sends the current thread sleeping and sets a reference variable.
Definition: chthreads.c:734
ch_list_pop
static ch_list_t * ch_list_pop(ch_list_t *lp)
Pops an element from the top of a stack list and returns it.
Definition: chlists.h:192
chThdDoDequeueNextI
static void chThdDoDequeueNextI(threads_queue_t *tqp, msg_t msg)
Dequeues and wakes up one thread from the threads queue object.
Definition: chthreads.h:428
chSchRescheduleS
void chSchRescheduleS(void)
Performs a reschedule if a higher priority thread is runnable.
Definition: chschd.c:339
ch_queue_init
static void ch_queue_init(ch_queue_t *qp)
Queue initialization.
Definition: chlists.h:207
chDbgCheckClassI
void chDbgCheckClassI(void)
I-class functions context check.
Definition: chdebug.c:233
CH_FLAG_TERMINATE
#define CH_FLAG_TERMINATE
Termination requested flag.
Definition: chschd.h:105
MSG_OK
#define MSG_OK
Normal wakeup message.
Definition: chschd.h:39
_thread_init
thread_t * _thread_init(thread_t *tp, const char *name, tprio_t prio)
Initializes a thread structure.
Definition: chthreads.c:88
chTMObjectInit
void chTMObjectInit(time_measurement_t *tmp)
Initializes a TimeMeasurement object.
Definition: chtm.c:109
ch_thread::time
volatile systime_t time
Thread consumed time in ticks.
Definition: chschd.h:187
chThdYield
void chThdYield(void)
Yields the time slot.
Definition: chthreads.c:717
CH_FLAG_MODE_STATIC
#define CH_FLAG_MODE_STATIC
Static thread.
Definition: chschd.h:100
chThdSleepUntilWindowed
systime_t chThdSleepUntilWindowed(systime_t prev, systime_t next)
Suspends the invoking thread until the system time arrives to the specified value.
Definition: chthreads.c:697
sysinterval_t
uint64_t sysinterval_t
Type of time interval.
Definition: chtime.h:119
chThdSleep
void chThdSleep(sysinterval_t time)
Suspends the invoking thread for the specified time.
Definition: chthreads.c:652
chThdSleepS
static void chThdSleepS(sysinterval_t ticks)
Suspends the invoking thread for the specified number of ticks.
Definition: chthreads.h:381
ch_thread::mpool
void * mpool
Memory Pool where the thread workspace is returned.
Definition: chschd.h:290
chThdCreate
thread_t * chThdCreate(const thread_descriptor_t *tdp)
Creates a new thread into a static memory area.
Definition: chthreads.c:280
chThdDequeueNextI
void chThdDequeueNextI(threads_queue_t *tqp, msg_t msg)
Dequeues and wakes up one thread from the threads queue object, if any.
Definition: chthreads.c:885
CH_STATE_QUEUED
#define CH_STATE_QUEUED
On a queue.
Definition: chschd.h:67
thread_descriptor_t::name
const char * name
Thread name.
Definition: chthreads.h:61
ch_thread::state
tstate_t state
Current thread state.
Definition: chschd.h:165
ch.h
ChibiOS/RT main include file.
MSG_TIMEOUT
#define MSG_TIMEOUT
Wakeup caused by a timeout condition.
Definition: chschd.h:40
chSysUnlock
static void chSysUnlock(void)
Leaves the kernel lock state.
Definition: chsys.h:367
ch_thread::stats
time_measurement_t stats
Thread statistics.
Definition: chschd.h:296
chThdResume
void chThdResume(thread_reference_t *trp, msg_t msg)
Wakes up a thread waiting on a thread reference object.
Definition: chthreads.c:835
REG_REMOVE
#define REG_REMOVE(tp)
Removes a thread from the registry list.
Definition: chregistry.h:83
ch_thread::exitcode
msg_t exitcode
Thread exit code.
Definition: chschd.h:208
ch_thread::waiting
ch_list_t waiting
Termination waiting list.
Definition: chschd.h:260
chThdExitS
void chThdExitS(msg_t msg)
Terminates the current thread.
Definition: chthreads.c:501
chThdStart
thread_t * chThdStart(thread_t *tp)
Resumes a thread created with chThdCreateI().
Definition: chthreads.c:379
chTimeIsInRangeX
static bool chTimeIsInRangeX(systime_t time, systime_t start, systime_t end)
Checks if the specified time is within the specified time range.
Definition: chtime.h:480
chThdRelease
void chThdRelease(thread_t *tp)
Releases a reference to a thread object.
Definition: chthreads.c:427
thread_descriptor_t::prio
tprio_t prio
Thread priority.
Definition: chthreads.h:73
chThdSleepUntil
void chThdSleepUntil(systime_t time)
Suspends the invoking thread until the system time arrives to the specified value.
Definition: chthreads.c:672
chThdGetSelfX
static thread_t * chThdGetSelfX(void)
Returns a pointer to the current thread_t.
Definition: chthreads.h:275
ch_queue_insert
static void ch_queue_insert(ch_queue_t *p, ch_queue_t *qp)
Inserts an element into a queue.
Definition: chlists.h:247
ch_thread::flags
tmode_t flags
Various thread flags.
Definition: chschd.h:169
chSchWakeupS
void chSchWakeupS(thread_t *ntp, msg_t msg)
Wakes up a thread.
Definition: chschd.c:295
CH_STATE_WTEXIT
#define CH_STATE_WTEXIT
Waiting a thread.
Definition: chschd.h:72
chThdExit
void chThdExit(msg_t msg)
Terminates the current thread.
Definition: chthreads.c:477
ch_threads_queue::queue
ch_queue_t queue
Threads queue header.
Definition: chschd.h:125
ch_list_init
static void ch_list_init(ch_list_t *lp)
List initialization.
Definition: chlists.h:138