ChibiOS  21.6.0
chregistry.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/chregistry.c
22  * @brief Threads registry code.
23  *
24  * @addtogroup registry
25  * @details Threads Registry related APIs and services.
26  * <h2>Operation mode</h2>
27  * The Threads Registry is a double linked list that holds all the
28  * active threads in the system.<br>
29  * Operations defined for the registry:
30  * - <b>First</b>, returns the first, in creation order, active thread
31  * in the system.
32  * - <b>Next</b>, returns the next, in creation order, active thread
33  * in the system.
34  * .
35  * The registry is meant to be mainly a debug feature, for example,
36  * using the registry a debugger can enumerate the active threads
37  * in any given moment or the shell can print the active threads
38  * and their state.<br>
39  * Another possible use is for centralized threads memory management,
40  * terminating threads can pulse an event source and an event handler
41  * can perform a scansion of the registry in order to recover the
42  * memory.
43  * @pre In order to use the threads registry the @p CH_CFG_USE_REGISTRY
44  * option must be enabled in @p chconf.h.
45  * @{
46  */
47 
48 #include <string.h>
49 
50 #include "ch.h"
51 
52 #if (CH_CFG_USE_REGISTRY == TRUE) || defined(__DOXYGEN__)
53 
54 /*===========================================================================*/
55 /* Module exported variables. */
56 /*===========================================================================*/
57 
58 /*===========================================================================*/
59 /* Module local types. */
60 /*===========================================================================*/
61 
62 /*===========================================================================*/
63 /* Module local variables. */
64 /*===========================================================================*/
65 
66 /*===========================================================================*/
67 /* Module local functions. */
68 /*===========================================================================*/
69 
70 /*===========================================================================*/
71 /* Module exported functions. */
72 /*===========================================================================*/
73 
74 /*
75  * OS signature in ROM plus debug-related information.
76  */
77 ROMCONST chdebug_t ch_debug = {
78  {'m', 'a', 'i', 'n'},
79  (uint8_t)0,
80  (uint8_t)sizeof (chdebug_t),
81  (uint16_t)(((unsigned)CH_KERNEL_MAJOR << 11U) |
82  ((unsigned)CH_KERNEL_MINOR << 6U) |
83  ((unsigned)CH_KERNEL_PATCH << 0U)),
84  (uint8_t)sizeof (void *),
85  (uint8_t)sizeof (systime_t),
86  (uint8_t)sizeof (thread_t),
87  (uint8_t)__CH_OFFSETOF(thread_t, hdr.pqueue.prio),
88  (uint8_t)__CH_OFFSETOF(thread_t, ctx),
89  (uint8_t)__CH_OFFSETOF(thread_t, rqueue.next),
90  (uint8_t)__CH_OFFSETOF(thread_t, rqueue.prev),
91  (uint8_t)__CH_OFFSETOF(thread_t, name),
92 #if (CH_DBG_ENABLE_STACK_CHECK == TRUE) || (CH_CFG_USE_DYNAMIC == TRUE)
93  (uint8_t)__CH_OFFSETOF(thread_t, wabase),
94 #else
95  (uint8_t)0,
96 #endif
97  (uint8_t)__CH_OFFSETOF(thread_t, state),
98  (uint8_t)__CH_OFFSETOF(thread_t, flags),
99 #if CH_CFG_USE_DYNAMIC == TRUE
100  (uint8_t)__CH_OFFSETOF(thread_t, refs),
101 #else
102  (uint8_t)0,
103 #endif
104 #if CH_CFG_TIME_QUANTUM > 0
105  (uint8_t)__CH_OFFSETOF(thread_t, ticks),
106 #else
107  (uint8_t)0,
108 #endif
110  (uint8_t)__CH_OFFSETOF(thread_t, time)
111 #else
112  (uint8_t)0
113 #endif
114 };
115 
116 /**
117  * @brief Returns the first thread in the system.
118  * @details Returns the most ancient thread in the system, usually this is
119  * the main thread unless it terminated. A reference is added to the
120  * returned thread in order to make sure its status is not lost.
121  * @note This function cannot return @p NULL because there is always at
122  * least one thread in the system.
123  *
124  * @return A reference to the most ancient thread.
125  *
126  * @api
127  */
129  thread_t *tp;
130  uint8_t *p;
131 
132  chSysLock();
133  p = (uint8_t *)REG_HEADER(currcore)->next;
134  /*lint -save -e413 [1.3] Safe to subtract a calculated offset.*/
135  tp = (thread_t *)(p - __CH_OFFSETOF(thread_t, rqueue));
136  /*lint -restore*/
137 #if CH_CFG_USE_DYNAMIC == TRUE
138  tp->refs++;
139 #endif
140  chSysUnlock();
141 
142  return tp;
143 }
144 
145 /**
146  * @brief Returns the thread next to the specified one.
147  * @details The reference counter of the specified thread is decremented and
148  * the reference counter of the returned thread is incremented.
149  *
150  * @param[in] tp pointer to the thread
151  * @return A reference to the next thread.
152  * @retval NULL if there is no next thread.
153  *
154  * @api
155  */
157  thread_t *ntp;
158  ch_queue_t *nqp;
159 
160  chSysLock();
161 
162  /* Next element in the registry queue.*/
163  nqp = tp->rqueue.next;
164  if (nqp == REG_HEADER(currcore)) {
165  ntp = NULL;
166  }
167 #if CH_CFG_USE_DYNAMIC == TRUE
168  else {
169  uint8_t *p = (uint8_t *)nqp;
170  /*lint -save -e413 [1.3] Safe to subtract a calculated offset.*/
171  ntp = (thread_t *)(p - __CH_OFFSETOF(thread_t, rqueue));
172  /*lint -restore*/
173 
174  chDbgAssert(ntp->refs < (trefs_t)255, "too many references");
175 
176  ntp->refs++;
177  }
178 #endif
179  chSysUnlock();
180 #if CH_CFG_USE_DYNAMIC == TRUE
181  chThdRelease(tp);
182 #endif
183 
184  return ntp;
185 }
186 
187 /**
188  * @brief Retrieves a thread pointer by name.
189  * @note The reference counter of the found thread is increased by one so
190  * it cannot be disposed incidentally after the pointer has been
191  * returned.
192  *
193  * @param[in] name the thread name
194  * @return A pointer to the found thread.
195  * @retval NULL if a matching thread has not been found.
196  *
197  * @api
198  */
199 thread_t *chRegFindThreadByName(const char *name) {
200  thread_t *ctp;
201 
202  /* Scanning registry.*/
203  ctp = chRegFirstThread();
204  do {
205  if (strcmp(chRegGetThreadNameX(ctp), name) == 0) {
206  return ctp;
207  }
208  ctp = chRegNextThread(ctp);
209  } while (ctp != NULL);
210 
211  return NULL;
212 }
213 
214 /**
215  * @brief Confirms that a pointer is a valid thread pointer.
216  * @note The reference counter of the found thread is increased by one so
217  * it cannot be disposed incidentally after the pointer has been
218  * returned.
219  *
220  * @param[in] tp pointer to the thread
221  * @return A pointer to the found thread.
222  * @retval NULL if a matching thread has not been found.
223  *
224  * @api
225  */
227  thread_t *ctp;
228 
229  /* Scanning registry.*/
230  ctp = chRegFirstThread();
231  do {
232  if (ctp == tp) {
233  return ctp;
234  }
235  ctp = chRegNextThread(ctp);
236  } while (ctp != NULL);
237 
238  return NULL;
239 }
240 
241 #if (CH_DBG_ENABLE_STACK_CHECK == TRUE) || (CH_CFG_USE_DYNAMIC == TRUE) || \
242  defined(__DOXYGEN__)
243 /**
244  * @brief Confirms that a working area is being used by some active thread.
245  * @note The reference counter of the found thread is increased by one so
246  * it cannot be disposed incidentally after the pointer has been
247  * returned.
248  *
249  * @param[in] wa pointer to a static working area
250  * @return A pointer to the found thread.
251  * @retval NULL if a matching thread has not been found.
252  *
253  * @api
254  */
256  thread_t *ctp;
257 
258  /* Scanning registry.*/
259  ctp = chRegFirstThread();
260  do {
261  if (chThdGetWorkingAreaX(ctp) == wa) {
262  return ctp;
263  }
264  ctp = chRegNextThread(ctp);
265  } while (ctp != NULL);
266 
267  return NULL;
268 }
269 #endif
270 
271 #endif /* CH_CFG_USE_REGISTRY == TRUE */
272 
273 /** @} */
ch_queue::next
ch_queue_t * next
Next in the list/queue.
Definition: chlists.h:70
ch_thread::pqueue
ch_priority_queue_t pqueue
Threads ordered queues element.
Definition: chobjects.h:172
stkalign_t
port_stkalign_t stkalign_t
Definition: chearly.h:80
currcore
#define currcore
Access to current core's instance structure.
Definition: chsys.h:90
CH_CFG_TIME_QUANTUM
#define CH_CFG_TIME_QUANTUM
Round robin interval.
Definition: rt/templates/chconf.h:128
chRegFindThreadByName
thread_t * chRegFindThreadByName(const char *name)
Retrieves a thread pointer by name.
Definition: chregistry.c:199
CH_KERNEL_MAJOR
#define CH_KERNEL_MAJOR
Kernel version major number.
Definition: rt/include/ch.h:56
systime_t
uint64_t systime_t
Type of system time.
Definition: chtime.h:107
__CH_OFFSETOF
#define __CH_OFFSETOF(st, m)
Structure field offset utility.
Definition: chearly.h:158
chDbgAssert
#define chDbgAssert(c, r)
Condition assertion.
Definition: chdebug.h:144
chRegGetThreadNameX
static const char * chRegGetThreadNameX(thread_t *tp)
Returns the name of the specified thread.
Definition: chregistry.h:168
chRegFindThreadByPointer
thread_t * chRegFindThreadByPointer(thread_t *tp)
Confirms that a pointer is a valid thread pointer.
Definition: chregistry.c:226
chThdGetWorkingAreaX
static stkalign_t * chThdGetWorkingAreaX(thread_t *tp)
Returns the working area base of the specified thread.
Definition: chthreads.h:386
ch_thread::refs
trefs_t refs
References to this thread.
Definition: chobjects.h:215
ch_thread
Structure representing a thread.
Definition: chobjects.h:156
chRegFindThreadByWorkingArea
thread_t * chRegFindThreadByWorkingArea(stkalign_t *wa)
Confirms that a working area is being used by some active thread.
Definition: chregistry.c:255
thread_t
struct ch_thread thread_t
Type of a thread structure.
Definition: chearly.h:133
CH_KERNEL_MINOR
#define CH_KERNEL_MINOR
Kernel version minor number.
Definition: rt/include/ch.h:61
ch_queue
Structure representing a generic bidirectional linked list header and element.
Definition: chlists.h:69
ROMCONST
#define ROMCONST
ROM constant modifier.
Definition: chtypes.h:84
chRegFirstThread
thread_t * chRegFirstThread(void)
Returns the first thread in the system.
Definition: chregistry.c:128
ch_thread::rqueue
ch_queue_t rqueue
Registry queue element.
Definition: chobjects.h:182
trefs_t
uint8_t trefs_t
Definition: chearly.h:85
REG_HEADER
#define REG_HEADER(oip)
Access to the registry list header.
Definition: chregistry.h:81
CH_DBG_THREADS_PROFILING
#define CH_DBG_THREADS_PROFILING
Debug option, threads profiling.
Definition: rt/templates/chconf.h:648
CH_KERNEL_PATCH
#define CH_KERNEL_PATCH
Kernel version patch number.
Definition: rt/include/ch.h:66
chRegNextThread
thread_t * chRegNextThread(thread_t *tp)
Returns the thread next to the specified one.
Definition: chregistry.c:156
ch_priority_queue::prio
tprio_t prio
Priority of this element.
Definition: chlists.h:88
TRUE
#define TRUE
Generic 'true' preprocessor boolean constant.
Definition: rt/include/ch.h:86
chThdRelease
void chThdRelease(thread_t *tp)
Releases a reference to a thread object.
Definition: chthreads.c:438
chdebug_t
ChibiOS/RT memory signature record.
Definition: chregistry.h:52
chSysUnlock
#define chSysUnlock()
Leaves the kernel lock state.
Definition: nil/include/ch.h:1053
chSysLock
#define chSysLock()
Enters the kernel lock state.
Definition: nil/include/ch.h:1043