LPCOpen Platform  v1.03
LPCOpen Platform for NXP LPC Microcontrollers
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
os_tls.c
Go to the documentation of this file.
1 /*
2 ************************************************************************************************************************
3 * uC/OS-III
4 * The Real-Time Kernel
5 *
6 * (c) Copyright 2009-2012; Micrium, Inc.; Weston, FL
7 * All rights reserved. Protected by international copyright laws.
8 *
9 * THREAD LOCAL STORAGE (TLS) MANAGEMENT
10 * Cross Core Embedded Studio (CCES) IMPLEMENTATION
11 *
12 * File : OS_TLS.C
13 * By : JJL
14 * Version : V3.03.00
15 *
16 * LICENSING TERMS:
17 * ---------------
18 * uC/OS-III is provided in source form for FREE short-term evaluation, for educational use or
19 * for peaceful research. If you plan or intend to use uC/OS-III in a commercial application/
20 * product then, you need to contact Micrium to properly license uC/OS-III for its use in your
21 * application/product. We provide ALL the source code for your convenience and to help you
22 * experience uC/OS-III. The fact that the source is provided does NOT mean that you can use
23 * it commercially without paying a licensing fee.
24 *
25 * Knowledge of the source code may NOT be used to develop a similar product.
26 *
27 * Please help us continue to provide the embedded community with the finest software available.
28 * Your honesty is greatly appreciated.
29 *
30 * You can contact us at www.micrium.com, or by phone at +1 (954) 217-2036.
31 ************************************************************************************************************************
32 */
33 
34 #define MICRIUM_SOURCE
35 #include <os.h>
36 
37 #ifdef VSC_INCLUDE_SOURCE_FILE_NAMES
38 const CPU_CHAR *os_tls__c = "$Id: $";
39 #endif
40 
41 #if defined(OS_CFG_TLS_TBL_SIZE) && (OS_CFG_TLS_TBL_SIZE > 0u)
42 /*
43 ************************************************************************************************************************
44 * LOCAL VARIABLES
45 ************************************************************************************************************************
46 */
47 
48 static CPU_DATA OS_TLS_NextAvailID; /* Next available TLS ID */
49 static OS_TLS_DESTRUCT_PTR OS_TLS_DestructPtrTbl[OS_CFG_TLS_TBL_SIZE];
50 
51 /*$PAGE*/
52 /*
53 ************************************************************************************************************************
54 * ALLOCATE THE NEXT AVAILABLE TLS ID
55 *
56 * Description: This function is called to obtain the ID of the next free TLS (Task Local Storage) register 'id'
57 *
58 * Arguments : p_err is a pointer to a variable that will hold an error code related to this call.
59 *
60 * OS_ERR_NONE if the call was successful
61 * OS_ERR_TLS_NO_MORE_AVAIL if you are attempting to assign more TLS than you declared
62 * available through OS_CFG_TLS_TBL_SIZE.
63 *
64 * Returns : The next available TLS 'id' or OS_CFG_TLS_TBL_SIZE if an error is detected.
65 ************************************************************************************************************************
66 */
67 
68 OS_TLS_ID OS_TLS_GetID (OS_ERR *p_err)
69 {
70  OS_TLS_ID id;
71  CPU_SR_ALLOC();
72 
73 
74 
75 #ifdef OS_SAFETY_CRITICAL
76  if (p_err == (OS_ERR *)0) {
77  OS_SAFETY_CRITICAL_EXCEPTION();
78  return ((OS_TLS_ID)OS_CFG_TLS_TBL_SIZE);
79  }
80 #endif
81 
83  if (OS_TLS_NextAvailID >= OS_CFG_TLS_TBL_SIZE) { /* See if we exceeded the number of IDs available */
84  *p_err = OS_ERR_TLS_NO_MORE_AVAIL; /* Yes, cannot allocate more TLS */
86  return ((OS_TLS_ID)OS_CFG_TLS_TBL_SIZE);
87  }
88 
89  id = OS_TLS_NextAvailID;
90  OS_TLS_NextAvailID++;
92  *p_err = OS_ERR_NONE;
93  return (id);
94 }
95 
96 /*$PAGE*/
97 /*
98 ************************************************************************************************************************
99 * GET THE CURRENT VALUE OF A TLS REGISTER
100 *
101 * Description: This function is called to obtain the current value of a TLS register
102 *
103 * Arguments : p_tcb is a pointer to the OS_TCB of the task you want to read the TLS register from. If 'p_tcb' is
104 * a NULL pointer then you will get the TLS register of the current task.
105 *
106 * id is the 'id' of the desired TLS register. Note that the 'id' must be less than
107 * 'OS_TLS_NextAvailID'
108 *
109 * p_err is a pointer to a variable that will hold an error code related to this call.
110 *
111 * OS_ERR_NONE if the call was successful
112 * OS_ERR_OS_NOT_RUNNING if the kernel has not started yet
113 * OS_ERR_TLS_ID_INVALID if the 'id' is greater or equal to OS_TLS_NextAvailID
114 * OS_ERR_TLS_NOT_EN if the task was created by specifying that TLS support was not
115 * needed for the task
116 *
117 * Returns : The current value of the task's TLS register or 0 if an error is detected.
118 *
119 * Note(s) : 1) p_tcb->Opt contains options passed to OSTaskCreate(). One of these options (OS_OPT_TASK_NO_TLS) is
120 * used to specify that the user doesn't want TLS support for the task being created. In other words,
121 * by default, TLS support is enabled if OS_CFG_TLS_TBL_SIZE is defined and > 0 so the user must
122 * specifically indicate that he/she doesn't want TLS supported for a task.
123 ************************************************************************************************************************
124 */
125 
126 OS_TLS OS_TLS_GetValue (OS_TCB *p_tcb,
127  OS_TLS_ID id,
128  OS_ERR *p_err)
129 {
130  OS_TLS value;
131  CPU_SR_ALLOC();
132 
133 
134 
135 #ifdef OS_SAFETY_CRITICAL
136  if (p_err == (OS_ERR *)0) {
137  OS_SAFETY_CRITICAL_EXCEPTION();
138  return ((OS_TLS)0);
139  }
140 #endif
141 
142 
143 #if OS_CFG_ARG_CHK_EN > 0u
144  if (id >= OS_TLS_NextAvailID) { /* Caller must specify an ID that's been assigned */
145  *p_err = OS_ERR_TLS_ID_INVALID;
146  return ((OS_TLS)0);
147  }
148 #endif
149 
151  if (p_tcb == (OS_TCB *)0) { /* Does caller want to use current task's TCB? */
152  p_tcb = OSTCBCurPtr; /* Yes */
153  if (OSTCBCurPtr == (OS_TCB *)0) { /* Is the kernel running? */
154  CPU_CRITICAL_EXIT(); /* No, then caller cannot specify NULL */
155  *p_err = OS_ERR_OS_NOT_RUNNING;
156  return ((OS_TLS)0);
157  }
158  }
159  if ((p_tcb->Opt & OS_OPT_TASK_NO_TLS) == OS_OPT_NONE) { /* See if TLS is available for this task */
160  value = p_tcb->TLS_Tbl[id]; /* Yes */
162  *p_err = OS_ERR_NONE;
163  return ((OS_TLS)value);
164  } else {
165  CPU_CRITICAL_EXIT(); /* No */
166  *p_err = OS_ERR_TLS_NOT_EN;
167  return ((OS_TLS)0);
168  }
169 }
170 
171 /*$PAGE*/
172 /*
173 ************************************************************************************************************************
174 * DEFINE TLS DESTRUCTOR FUNCTION
175 *
176 * Description: This function is called by the user to assign a 'destructor' function to a specific TLS. When a task is
177 * deleted, all the destructors are called for all the task's TLS for which there is a destructor function
178 * defined. In other when a task is deleted, all the non-NULL functions present in OS_TLS_DestructPtrTbl[]
179 * will be called.
180 *
181 * Arguments : id is the ID of the TLS destructor to set
182 *
183 * p_destruct is a pointer to a function that is associated with a specific TLS register and is called when
184 * a task is deleted. The prototype of such functions is:
185 *
186 * void MyDestructFunction (OS_TCB *p_tcb,
187 * OS_TLS_ID id,
188 * OS_TLS value);
189 *
190 * you can specify a NULL pointer if you don't want to have a fucntion associated with a TLS
191 * register. A NULL pointer (i.e. no function associated with a TLS register) is the default
192 * value placed in OS_TLS_DestructPtrTbl[].
193 *
194 * p_err is a pointer to an error return code. The possible values are:
195 *
196 * OS_ERR_NONE The call was successful.
197 * OS_ERR_TLS_ID_INVALID You you specified an invalid TLS ID
198 * OS_ERR_TLS_DESTRUCT_ASSIGNED If a destructor has already been assigned to the TLS ID
199 *
200 * Returns : none
201 *
202 * Note : none
203 ************************************************************************************************************************
204 */
205 
206 void OS_TLS_SetDestruct (OS_TLS_ID id,
207  OS_TLS_DESTRUCT_PTR p_destruct,
208  OS_ERR *p_err)
209 {
210  CPU_SR_ALLOC();
211 
212 
213 #ifdef OS_SAFETY_CRITICAL
214  if (p_err == (OS_ERR *)0) {
215  OS_SAFETY_CRITICAL_EXCEPTION();
216  return;
217  }
218 #endif
219 
220  if (id >= OS_TLS_NextAvailID) { /* See if we exceeded the number of TLS IDs available */
221  *p_err = OS_ERR_TLS_ID_INVALID;
222  return;
223  }
224 
225  if (OS_TLS_DestructPtrTbl[id] != (OS_TLS_DESTRUCT_PTR)0) { /* Can only assign a destructor once */
227  return;
228  }
229 
231  OS_TLS_DestructPtrTbl[id] = p_destruct;
233  *p_err = OS_ERR_NONE;
234 }
235 
236 /*$PAGE*/
237 /*
238 ************************************************************************************************************************
239 * SET THE CURRENT VALUE OF A TASK TLS REGISTER
240 *
241 * Description: This function is called to change the current value of a task TLS register.
242 *
243 * Arguments : p_tcb is a pointer to the OS_TCB of the task you want to set the task's TLS register for. If 'p_tcb'
244 * is a NULL pointer then you will change the TLS register of the current task.
245 *
246 * id is the 'id' of the desired task TLS register. Note that the 'id' must be less than
247 * 'OS_TLS_NextAvailID'
248 *
249 * value is the desired value for the task TLS register.
250 *
251 * p_err is a pointer to a variable that will hold an error code related to this call.
252 *
253 * OS_ERR_NONE if the call was successful
254 * OS_ERR_OS_NOT_RUNNING if the kernel has not started yet
255 * OS_ERR_TLS_ID_INVALID if you specified an invalid TLS ID
256 * OS_ERR_TLS_NOT_EN if the task was created by specifying that TLS support was not
257 * needed for the task
258 *
259 * Returns : none
260 *
261 * Note(s) : 1) p_tcb->Opt contains options passed to OSTaskCreate(). One of these options (OS_OPT_TASK_NO_TLS) is
262 * used to specify that the user doesn't want TLS support for the task being created. In other words,
263 * by default, TLS support is enabled if OS_CFG_TLS_TBL_SIZE is defined and > 0 so the user must
264 * specifically indicate that he/she doesn't want TLS supported for a task.
265 ************************************************************************************************************************
266 */
267 
268 void OS_TLS_SetValue (OS_TCB *p_tcb,
269  OS_TLS_ID id,
270  OS_TLS value,
271  OS_ERR *p_err)
272 {
273  CPU_SR_ALLOC();
274 
275 
276 
277 #ifdef OS_SAFETY_CRITICAL
278  if (p_err == (OS_ERR *)0) {
279  OS_SAFETY_CRITICAL_EXCEPTION();
280  return;
281  }
282 #endif
283 
284 #if OS_CFG_ARG_CHK_EN > 0u
285  if (id >= OS_TLS_NextAvailID) { /* Caller must specify an ID that's been assigned */
286  *p_err = OS_ERR_TLS_ID_INVALID;
287  return;
288  }
289 #endif
290 
291  CPU_CRITICAL_ENTER(); /* Does caller want to use current task's TCB? */
292  if (p_tcb == (OS_TCB *)0) { /* Yes */
293  p_tcb = OSTCBCurPtr; /* Is the kernel running? */
294  if (OSTCBCurPtr == (OS_TCB *)0) { /* No, then caller cannot specify NULL */
296  *p_err = OS_ERR_OS_NOT_RUNNING;
297  return;
298  }
299  }
300  if ((p_tcb->Opt & OS_OPT_TASK_NO_TLS) == OS_OPT_NONE) { /* See if TLS is available for this task */
301  p_tcb->TLS_Tbl[id] = value; /* Yes */
303  *p_err = OS_ERR_NONE;
304  } else {
305  CPU_CRITICAL_EXIT(); /* No */
306  *p_err = OS_ERR_TLS_NOT_EN;
307  }
308 }
309 
310 /*$PAGE*/
311 /*
312 ************************************************************************************************************************
313 ************************************************************************************************************************
314 * uC/OS-III INTERNAL FUNCTIONS
315 * DO NOT CALL FROM THE APPLICATION CODE
316 ************************************************************************************************************************
317 ************************************************************************************************************************
318 */
319 
320 /*
321 ************************************************************************************************************************
322 * INITIALIZE THE TASK LOCAL STORAGE SERVICES
323 *
324 * Description: This function is called by uC/OS-III to initialize the TLS id allocator.
325 *
326 * This function also initializes an array containing function pointers. There is one function associated
327 * to each task TLS register and all the functions (assuming non-NULL) will be called when the task is
328 * deleted.
329 *
330 * Arguments : p_err is a pointer to an error return value. Current error can be:
331 *
332 * OS_ERR_NONE if the call was successful
333 *
334 * Returns : none
335 *
336 * Note : This function is INTERNAL to uC/OS-III and your application should not call it.
337 ************************************************************************************************************************
338 */
339 
340 void OS_TLS_Init (OS_ERR *p_err)
341 {
342  OS_TLS_ID i;
343 
344 
345 
346  OS_TLS_NextAvailID = 0u;
347 
348  for (i = 0u; i < OS_CFG_TLS_TBL_SIZE; i++) {
349  OS_TLS_DestructPtrTbl[i] = (OS_TLS_DESTRUCT_PTR)0;
350  }
351  *p_err = OS_ERR_NONE;
352 }
353 
354 /*$PAGE*/
355 /*
356 ************************************************************************************************************************
357 * TASK CREATE HOOK
358 *
359 * Description: This function is called by OSTaskCreate()
360 *
361 * Arguments : p_tcb is a pointer to the OS_TCB of the task being created.
362 *
363 * Returns : none
364 *
365 * Note(s) : 1) This function is INTERNAL to uC/OS-III and your application should not call it.
366 *
367 * 2) OSTaskCreate() clears all entries in p_tcb->TLS_Tbl[] before calling OS_TLS_TaskCreate() so no need
368 * to this here.
369 ************************************************************************************************************************
370 */
371 
372 void OS_TLS_TaskCreate (OS_TCB *p_tcb)
373 {
374  (void)&p_tcb;
375 }
376 
377 /*$PAGE*/
378 /*
379 ************************************************************************************************************************
380 * TASK DELETE HOOK
381 *
382 * Description: This function is called by OSTaskDel()
383 *
384 * Arguments : p_tcb is a pointer to the OS_TCB of the task being deleted.
385 *
386 * Returns : none
387 *
388 * Note(s) : 1) This function is INTERNAL to uC/OS-III and your application should not call it.
389 ************************************************************************************************************************
390 */
391 
392 void OS_TLS_TaskDel (OS_TCB *p_tcb)
393 {
394  OS_TLS_ID id;
395  OS_TLS_DESTRUCT_PTR *p_tbl;
396 
397 
398  for (id = 0; id < OS_TLS_NextAvailID; id++) { /* Call all the destructors associated with the TLS IDs */
399  p_tbl = &OS_TLS_DestructPtrTbl[id];
400  if (*p_tbl != (OS_TLS_DESTRUCT_PTR)0) {
401  (*p_tbl)(p_tcb, id, p_tcb->TLS_Tbl[id]);
402  }
403  }
404 }
405 
406 /*$PAGE*/
407 /*
408 ************************************************************************************************************************
409 * TASK SWITCH HOOK
410 *
411 * Description: This function is called by OSSched() and OSIntExit() just prior to calling the context switch code
412 *
413 * Arguments : none
414 *
415 * Returns : none
416 *
417 * Note(s) : 1) This function is INTERNAL to uC/OS-III and your application should not call it.
418 *
419 * 2) It's assumed that OSTCBCurPtr points to the task being switched out and OSTCBHighRdyPtr points to the
420 * task being switched in.
421 ************************************************************************************************************************
422 */
423 
424 void OS_TLS_TaskSw (void)
425 {
426 }
427 #endif
428 
429