PIC24 Support Libraries
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
esos_task.h
Go to the documentation of this file.
1 /*
2  * "Copyright (c) 2008 Robert B. Reese, Bryan A. Jones, J. W. Bruce ("AUTHORS")"
3  * All rights reserved.
4  * (R. Reese, reese_AT_ece.msstate.edu, Mississippi State University)
5  * (B. A. Jones, bjones_AT_ece.msstate.edu, Mississippi State University)
6  * (J. W. Bruce, jwbruce_AT_ece.msstate.edu, Mississippi State University)
7  *
8  * Permission to use, copy, modify, and distribute this software and its
9  * documentation for any purpose, without fee, and without written agreement is
10  * hereby granted, provided that the above copyright notice, the following
11  * two paragraphs and the authors appear in all copies of this software.
12  *
13  * IN NO EVENT SHALL THE "AUTHORS" BE LIABLE TO ANY PARTY FOR
14  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
15  * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE "AUTHORS"
16  * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
17  *
18  * THE "AUTHORS" SPECIFICALLY DISCLAIMS ANY WARRANTIES,
19  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
20  * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
21  * ON AN "AS IS" BASIS, AND THE "AUTHORS" HAS NO OBLIGATION TO
22  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
23  *
24  * Please maintain this header in its entirety when copying/modifying
25  * these files.
26  *
27  *
28  */
29 
30 /*
31  * This file defines the macros and structures needed to implement the
32  * ESOS cooperative mulitasking. It relies heavily on the PROTOTHREADS
33  * library created by Adam Dunkels at SICS. The SICS notices are
34  * found at the EOF.
35  */
36 
37 /**
38  * \addtogroup ESOS_Tasks
39  * @{
40  */
41 
42 /** \file
43  * This file contains macros for creating and managing
44  * ESOS tasks and semaphores. User need not include
45  * this file, but rather should include \ref esos.h
46  * instead.
47  */
48 
49 #ifndef __ESOS_TASK_H__
50 #define __ESOS_TASK_H__
51 
52 #include "lc.h"
53 
54 struct stTask {
55  lc_t lc;
56  uint8 flags;
57  uint8 (*pfn)(struct stTask *);
58  uint32 u32_savedTick;
59  uint32 u32_waitLen;
60 };
61 
62 /** \struct ESOS_TASK_HANDLE
63  * Handle to an ESOS user task. This handle is used whenever a
64  * task needs to refer to another task, or whenever a task needs
65  * to retreive its own handle.
66  *
67  * \sa ESOS_TASK_GET_TASK_HANDLE
68  * \sa ESOS_ALLOCATE_CHILD_TASK
69  *
70  */
71 typedef struct stTask* ESOS_TASK_HANDLE;
72 
73 /* Task "return" values. Used by scheduler to determine what to do with task **/
74 #define ESOS_TASK_WAITING 0
75 #define ESOS_TASK_ENDED 3
76 
77 /* Task flag : task has ended (hit ESOS_TASK_END) */
78 #define __TASK_ENDED_MASK BIT3
79 /* Task flag : task has been flagged to be killed (will exit on next block/wait/yield) */
80 #define __TASK_KILLED_MASK BIT2
81 /* Task flag : task is sleeping */
82 #define __TASK_SLEEPING_MASK BIT1
83 /* Task flag : task is waiting */
84 #define __TASK_WAITING_MASK BIT0
85 /* Task flag : task has been called by scheduler */
86 #define __TASK_CALLED_MASK BIT7
87 
88 /* some helper macros to manage Task states **/
89 #define __ESOS_SET_TASK_SLEEPING_FLAG(TaskHandle) BIT_SET_MASK((TaskHandle)->flags, __TASK_SLEEPING_MASK)
90 #define __ESOS_CLEAR_TASK_SLEEPING_FLAG(TaskHandle) BIT_CLEAR_MASK((TaskHandle)->flags, __TASK_SLEEPING_MASK)
91 #define __ESOS_SET_TASK_KILLED_FLAG(TaskHandle) BIT_SET_MASK((TaskHandle)->flags, __TASK_KILLED_MASK)
92 #define __ESOS_CLEAR_TASK_KILLED_FLAG(TaskHandle) BIT_CLEAR_MASK((TaskHandle)->flags, __TASK_KILLED_MASK)
93 #define __ESOS_SET_TASK_WAITING_FLAG(TaskHandle) BIT_SET_MASK((TaskHandle)->flags, __TASK_WAITING_MASK)
94 #define __ESOS_CLEAR_TASK_WAITING_FLAG(TaskHandle) BIT_CLEAR_MASK((TaskHandle)->flags, __TASK_WAITING_MASK)
95 #define __ESOS_SET_TASK_CALLED_FLAG(TaskHandle) BIT_SET_MASK((TaskHandle)->flags, __TASK_CALLED_MASK)
96 #define __ESOS_CLEAR_TASK_CALLED_FLAG(TaskHandle) BIT_CLEAR_MASK((TaskHandle)->flags, __TASK_CALLED_MASK)
97 #define __ESOS_IS_TASK_CALLED(TaskHandle) IS_BIT_SET_MASK((TaskHandle)->flags, __TASK_CALLED_MASK)
98 #define __ESOS_SET_TASK_ENDED_FLAG(TaskHandle) BIT_SET_MASK((TaskHandle)->flags, __TASK_ENDED_MASK)
99 #define __ESOS_CLEAR_TASK_ENDED_FLAG(TaskHandle) BIT_CLEAR_MASK((TaskHandle)->flags, __TASK_ENDED_MASK)
100 
101 
102 /**
103  * \name Initialization
104  * @{
105  */
106 
107 /**
108  * Initialize an ESOS task.
109  *
110  * Initializes an ESOS task. Initialization must be done prior to
111  * starting to execute the task.
112  *
113  * \note Called by ESOS internally. Users have no real reason to call this function
114  * themselves.
115  * \param TaskHandle The \ref ESOS_TASK_HANDLE of the task to be initialized
116  * \sa ESOS_TASK_SPAWN_AND_WAIT
117  * \sa ESOS_TASK_GET_TASK_HANDLE
118  * \hideinitializer
119  */
120 #define __ESOS_INIT_TASK(TaskHandle) \
121  LC_INIT((TaskHandle)->lc);
122 
123 /** @} */
124 
125 /**
126  * \name Querying the state of a task
127  * @{
128  */
129 
130 /**
131  * Is ESOS task structure initialized?.
132  *
133  * Checks to see of the ESOS task structure is initialized. Initialization must be done prior to
134  * starting to execute the task. In reality, this checks to see if a task structure is available
135  * since a 'running' task structure will appear to be uninitialized since its state will not be
136  * NULL, ZERO, or whatever our implementation of uses as the initial state.
137  *
138  * \param TaskHandle The \ref ESOS_TASK_HANDLE of the task being queried
139  *
140  * \sa __ESOS_INIT_TASK
141  *
142  * \hideinitializer
143  */
144 #define ESOS_IS_TASK_INITED(TaskHandle) LC_IS_INITED((TaskHandle)->lc)
145 
146 /**
147  * Determines if a task is currently sleeping
148  *
149  * \param TaskHandle The \ref ESOS_TASK_HANDLE of the task being queried
150  * \sa ESOS_TASK_GET_TASK_HANDLE
151  * \hideinitializer
152  */
153 #define ESOS_IS_TASK_SLEEPING(TaskHandle) IS_BIT_SET_MASK((TaskHandle)->flags, __TASK_SLEEPING_MASK)
154 
155 /**
156  * Determines if a task is slated to be killed at its next execution.
157  *
158  * \param TaskHandle The \ref ESOS_TASK_HANDLE of the task being queried
159  * \sa ESOS_TASK_GET_TASK_HANDLE
160  * \hideinitializer
161  */
162 #define ESOS_IS_TASK_KILLED(TaskHandle) IS_BIT_SET_MASK((TaskHandle)->flags, __TASK_KILLED_MASK)
163 
164 /**
165  * Determines if a task is waiting to run/blocked by some condition.
166  *
167  * \param TaskHandle The \ref ESOS_TASK_HANDLE of the task being queried
168  * \sa ESOS_TASK_GET_TASK_HANDLE
169  * \hideinitializer
170  */
171 #define ESOS_IS_TASK_WAITING(TaskHandle) IS_BIT_SET_MASK((TaskHandle)->flags, __TASK_WAITING_MASK)
172 
173 /**
174  * Determines if a task is inactive/ended. Tasks in this state
175  * are subject to culling by the ESOS scheduler at some point in
176  * future.
177  *
178  * \param TaskHandle The \ref ESOS_TASK_HANDLE of the task being queried
179  * \sa ESOS_TASK_GET_TASK_HANDLE
180  * \hideinitializer
181  */
182 #define ESOS_IS_TASK_ENDED(TaskHandle) IS_BIT_SET_MASK((TaskHandle)->flags, __TASK_ENDED_MASK)
183 
184 /** @} */
185 
186 /**
187  * \name Declaration and definition
188  * @{
189  */
190 
191 /**
192  * Declaration of an ESOS task.
193  *
194  * This macro is used to declare an ESOS task. All ESOS tasks must
195  * be declared with this macro.
196  *
197  * \note ESOS tasks have no arguments passed in and cannot return values.
198  * \param taskname The name by which you wish for the user task to be known.
199  * In reality, this name is the name of the C function implementing the ESOS
200  * task. Therefore, your task names must be unique and adhere to C language
201  * naming restrictions.
202  *
203  * \hideinitializer
204  */
205 #define ESOS_USER_TASK(taskname) uint8 taskname(ESOS_TASK_HANDLE __pstSelf)
206 
207 /**
208  * Declaration of an ESOS child task -- a task spawned by another
209  * ESOS task (a.k.a. the parent task)
210  *
211  * This macro is used to declare an ESOS child task. All ESOS child
212  * tasks must be declared with this macro. This macro relies on the
213  * compiler's ability to handle variadic arguments. GCC does this
214  * just fine. Other compilers may not work.
215  *
216  * \note ESOS child tasks can have zero or more input arguments passed in.
217  * However, ESOS child tasks <em>cannot</em> return values.
218  * \param taskname The name by which you wish for the child task to be known. In
219  * reality, this name is the name of a C function implementing the ESOS child task.
220  * \param ... (OPTIONAL) Any arguments to pass to the the child task
221  *
222  * \hideinitializer
223  */
224 #define ESOS_CHILD_TASK(taskname, ...) uint8 taskname(ESOS_TASK_HANDLE __pstSelf, ##__VA_ARGS__)
225 
226 /**
227  * Declare the start of an ESOS task inside the C function
228  * implementing the ESOS task.
229  *
230  * This macro is used to declare the starting point of a
231  * ESOS task. It should be placed at the start of the function in
232  * which the ESOS task runs. All C statements above the ESOS_TASK_BEGIN()
233  * invokation will be executed each time the ESOS task is scheduled.
234  * \sa ESOS_TASK_END
235  * \hideinitializer
236  */
237 #define ESOS_TASK_BEGIN() \
238  { __ESOS_SET_TASK_CALLED_FLAG(__pstSelf); \
239  LC_RESUME(__pstSelf->lc)
240 
241 /**
242  * Declare the end of an ESOS task.
243  *
244  * This macro is used for declaring that an ESOS task ends. It must
245  * always be used together with a matching ESOS_TASK_BEGIN() macro.
246  * \sa ESOS_TASK_BEGIN
247  * \hideinitializer
248  */
249 #define ESOS_TASK_END() \
250  LC_END(__pstSelf->lc); \
251  __pstSelf->flags = __TASK_ENDED_MASK; \
252  __ESOS_INIT_TASK(__pstSelf); \
253  return ESOS_TASK_ENDED; }
254 
255 
256 /**
257  * Retrieve the task handle for the current task.
258  *
259  * This macro gets the task handle for the current task. Useful
260  * if the current task wishes to give its handle to some other task
261  * so that the other task can manipulate the current task externally.
262  *
263  * \sa ESOS_TASK_WAKE
264  * \sa ESOS_TASK_KILL
265  * \hideinitializer
266  */
267 #define ESOS_TASK_GET_TASK_HANDLE() __pstSelf
268 
269 /** @} */
270 
271 /**
272  * \name Calling an ESOS task
273  * @{
274  */
275 
276 /**
277  * Schedule an ESOS task.
278  *
279  * This function schedules an ESOS task. The return value of the
280  * function is non-zero if the ESOS task is running or zero if the
281  * ESOS task has exited.
282  *
283  * \note Typically, this macro is only called by other ESOS task macros and
284  * the ESOS task scheduler. I can't think of any reasonable reason why an
285  * user would need to call this macro!
286  * \param pfnThread The call to the C function implementing the ESOS task to
287  * be scheduled
288  *
289  * \hideinitializer
290  */
291 #define ESOS_SCHEDULE_TASK(pfnThread) ( (pfnThread) < ESOS_TASK_ENDED )
292 
293 /** @} */
294 
295 
296 /**
297  * \name Blocked waits
298  * @{
299  */
300 
301 /**
302  * Block and wait until condition is true.
303  *
304  * This macro blocks the ESOS task until the specified condition is
305  * true.
306  *
307  * \param condition The condition.
308  *
309  * \sa ESOS_TASK_WAIT_WHILE
310  *
311  * \hideinitializer
312  */
313 #define ESOS_TASK_WAIT_UNTIL(condition) \
314  do { \
315  LC_SET(__pstSelf->lc); \
316  if(ESOS_IS_TASK_KILLED(__pstSelf)) { \
317  __pstSelf->flags = __TASK_KILLED_MASK; \
318  return ESOS_TASK_ENDED; \
319  } \
320  if((condition)) { \
321  __ESOS_CLEAR_TASK_WAITING_FLAG(__pstSelf); \
322  } \
323  else { \
324  __ESOS_SET_TASK_WAITING_FLAG(__pstSelf); \
325  } \
326  if(ESOS_IS_TASK_WAITING(__pstSelf)) { \
327  return ESOS_TASK_WAITING; \
328  } \
329  } while(0)
330 
331 /**
332  * Block and wait while condition is true.
333  *
334  * This function blocks and waits while the specified condition is true.
335  * \param cond The condition.
336  *
337  * \sa ESOS_TASK_WAIT_UNTIL
338  *
339  * \hideinitializer
340  */
341 #define ESOS_TASK_WAIT_WHILE(cond) ESOS_TASK_WAIT_UNTIL(!(cond))
342 
343 /**
344  * Block and wait for a period of time/ticks
345  *
346  * This function blocks and waits for the duration of time requested.
347  *
348  * \param u32_duration Number of system ticks (currently milliseconds)
349  * to block
350  *
351  * \hideinitializer
352  */
353 #define ESOS_TASK_WAIT_TICKS(u32_duration) \
354 do { \
355  __pstSelf->u32_savedTick = esos_GetSystemTick(); \
356  __pstSelf->u32_waitLen = (u32_duration); \
357  ESOS_TASK_WAIT_UNTIL(__esos_hasTickDurationPassed(__pstSelf->u32_savedTick, __pstSelf->u32_waitLen) ); \
358 } while(0);
359 
360 /** @} */
361 
362 /* helper function to spawn child tasks */
363 #define __ESOS_TASK_SPAWN(pstChild, fcnCallWithArgs) \
364  do { \
365  __ESOS_INIT_TASK((pstChild)); \
366  ESOS_TASK_WAIT_THREAD((fcnCallWithArgs)); \
367  } while(0)
368 
369 /**
370  * \name Tasks and child tasks
371  * @{
372  */
373 
374 /**
375  * Block and wait until a child ESOS task completes.
376  *
377  * This macro schedules a child ESOS task. The current ESOS task
378  * will block until the child ESOS task completes.
379  *
380  * \todo I THINK THIS SHOULD BE REWRITTEN TO USE THE ESOS TASK STATE
381  * VARIABLES INSTEAD OF A CALL TO ESOS_SCHEDULE_TASK. DOESN'T WORK
382  * FOR BOTH PARENT AND CHILD TASKS AS WRITTEN!
383  *
384  * \note The child ESOS task must be manually initialized with the
385  * \ref __ESOS_INIT_TASK function before this function is used.
386  * \note Child task should have been defined with \ref ESOS_CHILD_TASK
387  *
388  * \param pfnChild Pointer to the child task function
389  * \param ... Arguments to the child task (if they exist)
390  *
391  * \sa ESOS_TASK_SPAWN_AND_WAIT
392  * \sa ESOS_CHILD_TASK
393  *
394  * \hideinitializer
395  */
396 #define ESOS_TASK_WAIT_THREAD(pfnChild, ...) ESOS_TASK_WAIT_WHILE(ESOS_SCHEDULE_TASK(pfnChild,##__VA_ARGS__ ))
397 
398 /**
399  * This macro initializes an ESOS child task structure, calls the child task and blocks
400  * the parent task until the child exits exits. The macro can only be used within an ESOS task.
401  *
402  * \param pstChild Pointer to the child ESOS task's control structure.
403  * \param pfnChild Pointer to the child task function
404  * \param ... Arguments to the child task (if they exist)
405  *
406  * \sa ESOS_TASK_WAIT_THREAD
407  * \sa ESOS_CHILD_TASK
408  *
409  * \note Child task should have been defined with \ref ESOS_CHILD_TASK
410  * \note Child task structure should have been obtained with \ref ESOS_ALLOCATE_CHILD_TASK
411  * \hideinitializer
412  */
413 #define ESOS_TASK_SPAWN_AND_WAIT(pstChild, pfnChild, ...) \
414  __ESOS_TASK_SPAWN((pstChild), (pfnChild)( (pstChild), ##__VA_ARGS__) )
415 
416 /**
417  * Allocates a child task storage structure in the local stack frame.
418  *
419  * This macro spawns a child ESOS task and waits until it exits. The
420  * macro can only be used within an ESOS task.
421  *
422  * \param pstName Name of variable to represent the allocated child task structure
423  * \hideinitializer
424  */
425 #define ESOS_ALLOCATE_CHILD_TASK(pstName) (pstName)=esos_GetFreeChildTaskStruct()
426 
427 /*
428  do { \
429  static ESOS_TASK_HANDLE pstName; \
430  pstName=esos_GetFreeChildTaskStruct(); \
431 } while(0)
432 */
433 
434 /** @} */
435 
436 /**
437  * \name Sleeping, killing, exiting and restarting tasks
438  * @{
439  */
440 
441 
442 /**
443  * Put the current task to sleep.
444  *
445  * This macro will cause the current task to "sleep" (block)
446  * until the task is awakened. The current task will not
447  * execute until it is explicitly wakened by some task caliing
448  * \ref ESOS_WAKE_TASK with the target task's identifier.
449  * The sleeping task will resume execution at the instruction
450  * following the ESOS_TASK_SLEEP().
451  *
452  * \sa ESOS_WAKE_TASK
453  *
454  * \hideinitializer
455  */
456 #define ESOS_TASK_SLEEP() \
457  do { \
458  __ESOS_SET_TASK_SLEEPING_FLAG(__pstSelf); \
459  ESOS_TASK_WAIT_WHILE(ESOS_IS_TASK_SLEEPING(__pstSelf)); \
460  } while(0)
461 
462 /**
463  * Restart the current ESOS task.
464  *
465  * This macro will block the current and cause the task to restart
466  * its execution at the place of the ESOS_TASK_BEGIN() call at its
467  * next scheduled execution time.
468  *
469  * \hideinitializer
470  */
471 #define ESOS_TASK_RESTART() \
472  do { \
473  __pstSelf->flags = 0; \
474  __ESOS_INIT_TASK(__pstSelf); \
475  return ESOS_TASK_WAITING; \
476  } while(0)
477 
478 /**
479  * Exit the current ESOS task.
480  *
481  * This macro causes the current ESOS task to exit. If the ESOS task was
482  * spawned by another ESOS task, the parent ESOS task will become
483  * unblocked and can continue to run.
484  *
485  * \sa ESOS_TASK_SPAWN
486  * \sa ESOS_TASK_WAIT_THREAD
487  *
488  * \hideinitializer
489  */
490 #define ESOS_TASK_EXIT() \
491  do { \
492  __pstSelf->flags = __TASK_ENDED_MASK; \
493  return ESOS_TASK_ENDED; \
494  } while(0)
495 
496 
497 /**
498  * Wake up a sleeping ESOS task.
499  *
500  * This macro will cause the target task to "wake" (resume)
501  * at its next opportunity. The sleeping task will resume
502  * execution at the instruction following the \ref ESOS_TASK_SLEEP
503  * that initially put the task to sleep.
504  *
505  * \param TaskHandle The \ref ESOS_TASK_HANDLE of the task to wake up.
506  * \sa ESOS_TASK_GET_TASK_HANDLE
507  * \sa ESOS_TASK_SLEEP
508  *
509  * \hideinitializer
510  */
511 #define ESOS_WAKE_TASK(TaskHandle) __ESOS_TASK_CLEAR_SLEEPING_FLAG((TaskHandle))
512 
513 /**
514  * Kill an scheduled ESOS task.
515  *
516  * This macro will cause the target task to "die" (exit)
517  * at its next scheduled execution.
518  * The target task will not execute any more instructions.
519  *
520  * \param TaskHandle The \ref ESOS_TASK_HANDLE of the task to kill
521  * \sa ESOS_TASK_GET_TASK_HANDLE
522  * \hideinitializer
523  */
524 #define ESOS_KILL_TASK(TaskHandle) __ESOS_TASK_SET_KILLED_FLAG((TaskHandle))
525 
526 
527 /**
528  * Restart a scheduled ESOS task
529  *
530  * This macro will cause the target task to "restart"
531  * (run from the beginning as if it were just created)
532  * at its next scheduled execution.
533  * \note Anything the target task has done and all of its
534  * local data variables and states will likely be lost.
535  * Do <em>NOT</em> restart another task unless you are very
536  * sure of how it will respond.
537  *
538  * \param TaskHandle The \ref ESOS_TASK_HANDLE of the task to kill
539  * \sa ESOS_TASK_GET_TASK_HANDLE
540  * \hideinitializer
541  */
542 #define ESOS_RESTART_TASK(TaskHandle) \
543  do { \
544  (TaskHandle)->flags = 0; \
545  __ESOS_INIT_TASK((TaskHandle)); \
546 } while(0)
547 
548 
549 /** @} */
550 
551 /**
552  * \name Yielding from an ESOS task
553  * @{
554  */
555 
556 /**
557  * Yield the current ESOS task.
558  *
559  * This function will yield the ESOS task IMMEDIATELY, thereby
560  * allowing other processing to take place in the system. The
561  * task will resume at the next instruction at its next invocation
562  * by the scheduler. (Of course, another task may "kill" it in
563  * the meantime and the task will not run again.)
564  *
565  * \hideinitializer
566  */
567 #define ESOS_TASK_YIELD() \
568  do { \
569  __ESOS_CLEAR_TASK_CALLED_FLAG(__pstSelf); \
570  ESOS_TASK_WAIT_UNTIL(__ESOS_IS_TASK_CALLED(__pstSelf)); \
571  } while(0)
572 
573 /** @} */
574 
575 /**
576  * ESOS semaphore structure
577  *
578  * \sa ESOS_INIT_SEMAPHORE
579  * \sa ESOS_TASK_WAIT_SEMAPHORE
580  * \sa ESOS_SIGNAL_SEMAPHORE
581  */
582 struct stSemaphore {
583  int16 i16_cnt;
584 };
585 
586 
587 /* Not using these with this definition of semaphores */
588 // #define _SEMNAME_CAT( name, line ) name##line
589 // #define _SEMNAME( name, line ) _SEMNAME_CAT( name, line )
590 // #define SEMNAME( name ) _SEMNAME( name, __LINE__ )
591 
592 /**
593  * \name Task semaphores
594  * @{
595  */
596 
597 /**
598  * Declare (and create storage for) an ESOS counting semaphore
599  * \param semaphoreName The name by which the semaphore is to be known
600  * \note Declares the memory storage space along with the
601  * ESOS_SEMAPHORE "object" that is used by user code.
602  * \note Since semaphores are typically used for synchronization,
603  * this macro to allocate storage for a semaphore should almost
604  * always be used in the "global" variable section of your application.
605  * \todo Make sure semaphores are safe in ISRs. Probably need to make
606  * semaphore storage and associated macros <em>volatile</em>
607  * \hideinitializer
608  */
609 #define ESOS_SEMAPHORE(semaphoreName) struct stSemaphore (semaphoreName)
610 
611 /**
612  * Initialize a semaphore
613  *
614  * This macro initializes a semaphore with a value for the
615  * counter. Internally, the semaphores use an "signed 16 bit integer" to
616  * represent the counter, and therefore the "count" argument should be
617  * between -32768 and +32767
618  *
619  * \param semaphoreName An ESOS semaphore created by \ref ESOS_SEMAPHORE
620  * \param i16_val (int16) The initial count of the semaphore.
621  * \sa ESOS_SEMAPHORE
622  * \sa ESOS_TASK_WAIT_SEMAPHORE
623  * \sa ESOS_SIGNAL_SEMAPHORE
624  *
625  * \hideinitializer
626  */
627 #define ESOS_INIT_SEMAPHORE(semaphoreName, i16_val) (semaphoreName).i16_cnt=(i16_val)
628 
629 /**
630  * Wait for a semaphore
631  *
632  * This macro carries out the "wait" operation on the semaphore. The
633  * wait operation causes the current ESOS task to block while the counter is
634  * zero. When the counter reaches a value larger than zero, the
635  * task will continue.
636  * \param semaphoreName An ESOS semaphore created by \ref ESOS_SEMAPHORE
637  * \param i16_val (int16) number to decrement semaphore value
638  * \sa ESOS_SEMAPHORE
639  * \sa ESOS_INIT_SEMAPHORE
640  * \sa ESOS_SIGNAL_SEMAPHORE
641  *
642  * \hideinitializer
643  */
644 #define ESOS_TASK_WAIT_SEMAPHORE(semaphoreName, i16_val) \
645  do { \
646  ESOS_TASK_WAIT_UNTIL((semaphoreName).i16_cnt >= (i16_val) ); \
647  (semaphoreName).i16_cnt -= (i16_val); \
648  } while(0)
649 
650 /**
651  * Signal a semaphore
652  *
653  * This macro carries out the "signal" operation on the semaphore. The
654  * signal operation increments the counter inside the semaphore, which
655  * eventually will cause waiting protothreads to continue executing.
656  * \param semaphoreName An ESOS semaphore created by \ref ESOS_SEMAPHORE
657  * \param i16_val (int16) number to decrement semaphore value
658  * \sa ESOS_SEMAPHORE
659  * \sa ESOS_TASK_WAIT_SEMAPHORE
660  * \sa ESOS_INIT_SEMAPHORE
661  *
662  * \hideinitializer
663  */
664 #define ESOS_SIGNAL_SEMAPHORE(semaphoreName, i16_val) (semaphoreName).i16_cnt+=(i16_val)
665 
666 /* @} */
667 
668 
669 #endif /* __ESOS_TASK_H__ */
670 
671 /** @} */
672 
673 /***********************************************************************
674  *
675  * MUCH OF THIS CODE IS BASED ON PROTOTHREADS BY ADAM DUNKELS
676  * AT THE SWEDISH INSTITUTE OF COMPUTER SCIENCE
677  *
678  ***********************************************************************
679  *
680  * Copyright (c) 2004-2005, Swedish Institute of Computer Science.
681  * All rights reserved.
682  *
683  * Redistribution and use in source and binary forms, with or without
684  * modification, are permitted provided that the following conditions
685  * are met:
686  * 1. Redistributions of source code must retain the above copyright
687  * notice, this list of conditions and the following disclaimer.
688  * 2. Redistributions in binary form must reproduce the above copyright
689  * notice, this list of conditions and the following disclaimer in the
690  * documentation and/or other materials provided with the distribution.
691  * 3. Neither the name of the Institute nor the names of its contributors
692  * may be used to endorse or promote products derived from this software
693  * without specific prior written permission.
694  *
695  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
696  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
697  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
698  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
699  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
700  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
701  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
702  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
703  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
704  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
705  * SUCH DAMAGE.
706  *
707  * This file is part of the Contiki operating system.
708  *
709  * Author: Adam Dunkels <adam@sics.se>
710  *
711  */