TNeo  v1.07
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
tn_tasks.h
Go to the documentation of this file.
1 /*******************************************************************************
2  *
3  * TNeo: real-time kernel initially based on TNKernel
4  *
5  * TNKernel: copyright © 2004, 2013 Yuri Tiomkin.
6  * PIC32-specific routines: copyright © 2013, 2014 Anders Montonen.
7  * TNeo: copyright © 2014 Dmitry Frank.
8  *
9  * TNeo was born as a thorough review and re-implementation of
10  * TNKernel. The new kernel has well-formed code, inherited bugs are fixed
11  * as well as new features being added, and it is tested carefully with
12  * unit-tests.
13  *
14  * API is changed somewhat, so it's not 100% compatible with TNKernel,
15  * hence the new name: TNeo.
16  *
17  * Permission to use, copy, modify, and distribute this software in source
18  * and binary forms and its documentation for any purpose and without fee
19  * is hereby granted, provided that the above copyright notice appear
20  * in all copies and that both that copyright notice and this permission
21  * notice appear in supporting documentation.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE DMITRY FRANK AND CONTRIBUTORS "AS IS"
24  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DMITRY FRANK OR CONTRIBUTORS BE
27  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
33  * THE POSSIBILITY OF SUCH DAMAGE.
34  *
35  ******************************************************************************/
36 
37 /**
38  * \file
39  *
40  * \section tn_tasks__tasks Task
41  *
42  * In TNeo, a task is a branch of code that runs concurrently with other
43  * tasks from the programmer's point of view. Indeed, tasks are actually
44  * executed using processor time sharing. Each task can be considered to be an
45  * independed program, which executes in its own context (processor registers,
46  * stack pointer, etc.).
47  *
48  * Actually, the term <i>thread</i> is more accurate than <i>task</i>, but the
49  * term <i>task</i> historically was used in TNKernel, so TNeo keeps this
50  * convention.
51  *
52  * When kernel decides that it's time to run another task, it performs
53  * <i>context switch</i>: current context (at least, values of all registers)
54  * gets saved to the preempted task's stack, pointer to currently running
55  * task is altered as well as stack pointer, and context gets restored from
56  * the stack of newly running task.
57  *
58  * \section tn_tasks__states Task states
59  *
60  * For list of task states and their description, refer to `enum
61  * #TN_TaskState`.
62  *
63  *
64  * \section tn_tasks__creating Creating/starting tasks
65  *
66  * Create task and start task are two separate actions; although you can
67  * perform both of them in one step by passing `#TN_TASK_CREATE_OPT_START` flag
68  * to the `tn_task_create()` function.
69  *
70  * \section tn_tasks__stopping Stopping/deleting tasks
71  *
72  * Stop task and delete task are two separate actions. If task was just stopped
73  * but not deleted, it can be just restarted again by calling
74  * `tn_task_activate()`. If task was deleted, it can't be just activated: it
75  * should be re-created by `tn_task_create()` first.
76  *
77  * Task stops execution when:
78  *
79  * - it calls `tn_task_exit()`;
80  * - it returns from its task body function (it is the equivalent to
81  * `tn_task_exit(0)`)
82  * - some other task calls `tn_task_terminate()` passing appropriate pointer to
83  * `struct #TN_Task`.
84  *
85  * \section tn_tasks__scheduling Scheduling rules
86  *
87  * TNeo always runs the most privileged task in state
88  * $(TN_TASK_STATE_RUNNABLE). In no circumstances can task run while there is
89  * at least one task is in the $(TN_TASK_STATE_RUNNABLE) state with higher
90  * priority. Task will run until:
91  *
92  * - It becomes non-runnable (say, it may wait for something, etc)
93  * - Some other task with higher priority becomes runnable.
94  *
95  * Tasks with the same priority may be scheduled in round robin fashion by
96  * getting a predetermined time slice for each task with this priority.
97  * Time slice is set separately for each priority. By default, round robin
98  * is turned off for all priorities.
99  *
100  * \section tn_tasks__idle Idle task
101  *
102  * TNeo has one system task: an idle task, which has lowest priority.
103  * It is always in the state $(TN_TASK_STATE_RUNNABLE), and it runs only when
104  * there are no other runnable tasks.
105  *
106  * User can provide a callback function to be called from idle task, see
107  * #TN_CBIdle. It is useful to bring the processor to some kind of real idle
108  * state, so that device draws less current.
109  *
110  */
111 
112 #ifndef _TN_TASKS_H
113 #define _TN_TASKS_H
114 
115 /*******************************************************************************
116  * INCLUDED FILES
117  ******************************************************************************/
118 
119 #include "tn_sys.h"
120 #include "tn_list.h"
121 #include "tn_common.h"
122 
123 #include "tn_eventgrp.h"
124 #include "tn_dqueue.h"
125 #include "tn_fmem.h"
126 #include "tn_timer.h"
127 
128 
129 
130 #ifdef __cplusplus
131 extern "C" { /*}*/
132 #endif
133 
134 /*******************************************************************************
135  * PUBLIC TYPES
136  ******************************************************************************/
137 
138 /**
139  * Task state
140  */
142  ///
143  /// This state should never be publicly available.
144  /// It may be stored in task_state only temporarily,
145  /// while some system service is in progress.
147  ///
148  /// Task is ready to run (it doesn't mean that it is running at the moment)
150  ///
151  /// Task is waiting. The reason of waiting can be obtained from
152  /// `task_wait_reason` field of the `struct TN_Task`.
153  ///
154  /// @see `enum #TN_WaitReason`
155  TN_TASK_STATE_WAIT = (1 << 1),
156  ///
157  /// Task is suspended (by some other task)
159  ///
160  /// Task was previously waiting, and after this it was suspended
162  ///
163  /// Task isn't yet activated or it was terminated by `tn_task_terminate()`.
165 
166 
167 };
168 
169 
170 /**
171  * Task wait reason
172  */
174  ///
175  /// Task isn't waiting for anything
177  ///
178  /// Task has called `tn_task_sleep()`
180  ///
181  /// Task waits to acquire a semaphore
182  /// @see tn_sem.h
184  ///
185  /// Task waits for some event in the event group to be set
186  /// @see tn_eventgrp.h
188  ///
189  /// Task wants to put some data to the data queue, and there's no space
190  /// in the queue.
191  /// @see tn_dqueue.h
193  ///
194  /// Task wants to receive some data to the data queue, and there's no data
195  /// in the queue
196  /// @see tn_dqueue.h
198  ///
199  /// Task wants to lock a mutex with priority ceiling
200  /// @see tn_mutex.h
202  ///
203  /// Task wants to lock a mutex with priority inheritance
204  /// @see tn_mutex.h
206  ///
207  /// Task wants to get memory block from memory pool, and there's no free
208  /// memory blocks
209  /// @see tn_fmem.h
211 
212 
213  ///
214  /// Wait reasons count
216 };
217 
218 /**
219  * Options for `tn_task_create()`
220  */
222  ///
223  /// whether task should be activated right after it is created.
224  /// If this flag is not set, user must activate task manually by calling
225  /// `tn_task_activate()`.
227  ///
228  /// for internal kernel usage only: this option must be provided
229  /// when creating idle task
231 };
232 
233 /**
234  * Options for `tn_task_exit()`
235  */
237  ///
238  /// whether task should be deleted right after it is exited.
239  /// If this flag is not set, user must either delete it manually by
240  /// calling `tn_task_delete()` or re-activate it by calling
241  /// `tn_task_activate()`.
243 };
244 
245 #if TN_PROFILER || DOXYGEN_ACTIVE
246 /**
247  * Timing structure that is managed by profiler and can be read by
248  * `#tn_task_profiler_timing_get()` function. This structure is contained in
249  * each `struct #TN_Task` structure.
250  *
251  * Available if only `#TN_PROFILER` option is non-zero, also depends on
252  * `#TN_PROFILER_WAIT_TIME`.
253  */
255  ///
256  /// Total time when task was running.
257  ///
258  /// \attention
259  /// This is NOT the time that task was in $(TN_TASK_STATE_RUNNABLE) state:
260  /// if task A is preempted by high-priority task B, task A is not running,
261  /// but is still in the $(TN_TASK_STATE_RUNNABLE) state. This counter
262  /// represents the time task was actually <b>running</b>.
263  unsigned long long total_run_time;
264  ///
265  /// How many times task got running. It is useful to find an average
266  /// value of consecutive running time: `(total_run_time / got_running_cnt)`
267  unsigned long long got_running_cnt;
268  ///
269  /// Maximum consecutive time task was running.
271 
272 #if TN_PROFILER_WAIT_TIME || DOXYGEN_ACTIVE
273  ///
274  /// Available if only `#TN_PROFILER_WAIT_TIME` option is non-zero.
275  ///
276  /// Total time when task was not running; time is broken down by reasons of
277  /// waiting.
278  ///
279  /// For example, to get the time task was waiting for mutexes with priority
280  /// inheritance protocol, use: `total_wait_time[ #TN_WAIT_REASON_MUTEX_I ]`
281  ///
282  /// To get the time task was runnable but preempted by another task, use:
283  /// `total_wait_time[ #TN_WAIT_REASON_NONE ]`
284  ///
285  unsigned long long total_wait_time[ TN_WAIT_REASONS_CNT ];
286  ///
287  /// Available if only `#TN_PROFILER_WAIT_TIME` option is non-zero.
288  ///
289  /// Maximum consecutive time task was not running; time is broken down by
290  /// reasons of waiting.
291  ///
292  /// @see `total_wait_time`
294 #endif
295 };
296 
297 /**
298  * Internal kernel structure for profiling data of task.
299  *
300  * Available if only `#TN_PROFILER` option is non-zero.
301  */
303  ///
304  /// Tick count of when the task got running or non-running last time.
306 #if TN_PROFILER_WAIT_TIME || DOXYGEN_ACTIVE
307  ///
308  /// Available if only `#TN_PROFILER_WAIT_TIME` option is non-zero.
309  ///
310  /// Value of `task->task_wait_reason` when task got non-running last time.
312 #endif
313 
314 #if TN_DEBUG
315  ///
316  /// For internal profiler self-check only: indicates whether task is
317  /// running or not. Available if only `#TN_DEBUG` is non-zero.
319 #endif
320  ///
321  /// Main timing structure managed by profiler. Contents of this structure
322  /// can be read by `#tn_task_profiler_timing_get()` function.
324 };
325 #endif
326 
327 /**
328  * Task
329  */
330 struct TN_Task {
331  /// pointer to task's current top of the stack;
332  /// Note that this field **must** be a first field in the struct,
333  /// this fact is exploited by platform-specific routines.
335  ///
336  /// id for object validity verification.
337  /// This field is in the beginning of the structure to make it easier
338  /// to detect memory corruption.
339  /// For `struct TN_Task`, we can't make it the very first field, since
340  /// stack pointer should be there.
342  ///
343  /// queue is used to include task in ready/wait lists
345  ///
346  /// timer object to implement task waiting for timeout
347  struct TN_Timer timer;
348  ///
349  /// pointer to object's (semaphore, mutex, event, etc) wait list in which
350  /// task is included for waiting
352  ///
353  /// queue is used to include task in creation list
354  /// (currently, this list is used for statistics only)
356 
357 #if TN_USE_MUTEXES
358  ///
359  /// list of all mutexes that are locked by task
361 #if TN_MUTEX_DEADLOCK_DETECT
362  ///
363  /// list of other tasks involved in deadlock. This list is non-empty
364  /// only in emergency cases, and it is here to help you fix your bug
365  /// that led to deadlock.
366  ///
367  /// @see `#TN_MUTEX_DEADLOCK_DETECT`
369 #endif
370 #endif
371 
372  ///-- lowest address of stack. It is independent of architecture:
373  /// it's always the lowest address (which may be actually origin
374  /// or end of stack, depending on the architecture)
376  ///-- Highest address of stack. It is independent of architecture:
377  /// it's always the highest address (which may be actually origin
378  /// or end of stack, depending on the architecture)
380  ///
381  /// pointer to task's body function given to `tn_task_create()`
383  ///
384  /// pointer to task's parameter given to `tn_task_create()`
386  ///
387  /// base priority of the task (actual current priority may be higher than
388  /// base priority because of mutex)
390  ///
391  /// current task priority
392  int priority;
393  ///
394  /// task state
396  ///
397  /// reason for waiting (relevant if only `task_state` is
398  /// $(TN_TASK_STATE_WAIT) or $(TN_TASK_STATE_WAITSUSP))
400  ///
401  /// waiting result code (reason why waiting finished)
403  //
404  // remaining time until timeout; may be `#TN_WAIT_INFINITE`.
405  //TN_TickCnt tick_count;
406  ///
407  /// time slice counter
409 #if 0
410  ///
411  /// last operation result code, might be used if some service
412  /// does not return that code directly
413  int last_rc;
414 #endif
415  ///
416  /// subsystem-specific fields that are used while task waits for something.
417  /// Do note that these fields are grouped by union, so, they must not
418  /// interfere with each other. It's quite ok here because task can't wait
419  /// for different things.
420  union {
421  /// fields specific to tn_eventgrp.h
423  ///
424  /// fields specific to tn_dqueue.h
426  ///
427  /// fields specific to tn_fmem.h
429  } subsys_wait;
430  ///
431  /// Task name for debug purposes, user may want to set it by hand
432  const char *name;
433 #if TN_PROFILER || DOXYGEN_ACTIVE
434  /// Profiler data, available if only `#TN_PROFILER` is non-zero.
436 #endif
437 
438  /// Internal flag used to optimize mutex priority algorithms.
439  /// For the comments on it, see file tn_mutex.c,
440  /// function `_mutex_do_unlock()`.
442 
443  /// Flag indicates that task waited for something
444  /// This flag is set automatially in `_tn_task_set_waiting()`
445  /// Must be cleared manually before calling any service that could sleep,
446  /// if the caller is interested in the relevant value of this flag.
447  unsigned waited : 1;
448 
449 
450 // Other implementation specific fields may be added below
451 
452 };
453 
454 
455 
456 /*******************************************************************************
457  * PROTECTED GLOBAL DATA
458  ******************************************************************************/
459 
460 /*******************************************************************************
461  * DEFINITIONS
462  ******************************************************************************/
463 
464 
465 
466 
467 /*******************************************************************************
468  * PUBLIC FUNCTION PROTOTYPES
469  ******************************************************************************/
470 
471 /**
472  * Construct task and probably start it (depends on options, see below).
473  * `id_task` member should not contain `#TN_ID_TASK`, otherwise,
474  * `#TN_RC_WPARAM` is returned.
475  *
476  * Usage example:
477  *
478  * \code{.c}
479  * #define MY_TASK_STACK_SIZE (TN_MIN_STACK_SIZE + 200)
480  * #define MY_TASK_PRIORITY 5
481  *
482  * struct TN_Task my_task;
483  *
484  * //-- define stack array, we use convenience macro TN_STACK_ARR_DEF()
485  * // for that
486  * TN_STACK_ARR_DEF(my_task_stack, MY_TASK_STACK_SIZE);
487  *
488  * void my_task_body(void *param)
489  * {
490  * //-- an endless loop
491  * for (;;){
492  * tn_task_sleep(1);
493  *
494  * //-- probably do something useful
495  * }
496  * }
497  * \endcode
498  *
499  *
500  *
501  * And then, somewhere from other task or from the callback
502  * `#TN_CBUserTaskCreate` given to `tn_sys_start()` :
503  * \code{.c}
504  * enum TN_RCode rc = tn_task_create(
505  * &my_task,
506  * my_task_body,
507  * MY_TASK_PRIORITY,
508  * my_task_stack,
509  * MY_TASK_STACK_SIZE,
510  * TN_NULL, //-- parameter isn't used
511  * TN_TASK_CREATE_OPT_START //-- start task on creation
512  * );
513  *
514  * if (rc != TN_RC_OK){
515  * //-- handle error
516  * }
517  * \endcode
518  *
519  * $(TN_CALL_FROM_TASK)
520  * $(TN_LEGEND_LINK)
521  *
522  * @param task
523  * Ready-allocated `struct TN_Task` structure. `id_task` member should not
524  * contain `#TN_ID_TASK`, otherwise `#TN_RC_WPARAM` is returned.
525  * @param task_func
526  * Pointer to task body function.
527  * @param priority
528  * Priority for new task. **NOTE**: the lower value, the higher priority.
529  * Must be > `0` and < `(#TN_PRIORITIES_CNT - 1)`.
530  * @param task_stack_low_addr
531  * Pointer to the stack for task.
532  * User must either use the macro `TN_STACK_ARR_DEF()` for the definition
533  * of stack array, or allocate it manually as an array of `#TN_UWord` with
534  * `#TN_ARCH_STK_ATTR_BEFORE` and `#TN_ARCH_STK_ATTR_AFTER` macros.
535  * @param task_stack_size
536  * Size of task stack array, in words (`#TN_UWord`), not in bytes.
537  * @param param
538  * Parameter that is passed to `task_func`.
539  * @param opts
540  * Options for task creation, refer to `enum #TN_TaskCreateOpt`
541  *
542  * @return
543  * * `#TN_RC_OK` on success;
544  * * `#TN_RC_WCONTEXT` if called from wrong context;
545  * * `#TN_RC_WPARAM` if wrong params were given;
546  *
547  * @see `#tn_task_create_wname()`
548  * @see `#TN_ARCH_STK_ATTR_BEFORE`
549  * @see `#TN_ARCH_STK_ATTR_AFTER`
550  */
552  struct TN_Task *task,
553  TN_TaskBody *task_func,
554  int priority,
555  TN_UWord *task_stack_low_addr,
556  int task_stack_size,
557  void *param,
558  enum TN_TaskCreateOpt opts
559  );
560 
561 
562 /**
563  * The same as `tn_task_create()` but with additional argument `name`,
564  * which could be very useful for debug.
565  */
567  struct TN_Task *task,
568  TN_TaskBody *task_func,
569  int priority,
570  TN_UWord *task_stack_low_addr,
571  int task_stack_size,
572  void *param,
573  enum TN_TaskCreateOpt opts,
574  const char *name
575  );
576 
577 /**
578  * If the task is $(TN_TASK_STATE_RUNNABLE), it is moved to the
579  * $(TN_TASK_STATE_SUSPEND) state. If the task is in the $(TN_TASK_STATE_WAIT)
580  * state, it is moved to the $(TN_TASK_STATE_WAITSUSP) state. (waiting +
581  * suspended)
582  *
583  * $(TN_CALL_FROM_TASK)
584  * $(TN_CAN_SWITCH_CONTEXT)
585  * $(TN_LEGEND_LINK)
586  *
587  * @param task Task to suspend
588  *
589  * @return
590  * * `#TN_RC_OK` on success;
591  * * `#TN_RC_WCONTEXT` if called from wrong context;
592  * * `#TN_RC_WSTATE` if task is already suspended or dormant;
593  * * If `#TN_CHECK_PARAM` is non-zero, additional return codes
594  * are available: `#TN_RC_WPARAM` and `#TN_RC_INVALID_OBJ`.
595  *
596  * @see `enum #TN_TaskState`
597  */
598 enum TN_RCode tn_task_suspend(struct TN_Task *task);
599 
600 /**
601  * Release task from $(TN_TASK_STATE_SUSPEND) state. If the given task is in
602  * the $(TN_TASK_STATE_SUSPEND) state, it is moved to $(TN_TASK_STATE_RUNNABLE)
603  * state; afterwards it has the lowest precedence among runnable tasks with the
604  * same priority. If the task is in $(TN_TASK_STATE_WAITSUSP) state, it is
605  * moved to $(TN_TASK_STATE_WAIT) state.
606  *
607  * $(TN_CALL_FROM_TASK)
608  * $(TN_CAN_SWITCH_CONTEXT)
609  * $(TN_LEGEND_LINK)
610  *
611  * @param task Task to release from suspended state
612  *
613  * @return
614  * * `#TN_RC_OK` on success;
615  * * `#TN_RC_WCONTEXT` if called from wrong context;
616  * * `#TN_RC_WSTATE` if task is not suspended;
617  * * If `#TN_CHECK_PARAM` is non-zero, additional return codes
618  * are available: `#TN_RC_WPARAM` and `#TN_RC_INVALID_OBJ`.
619  *
620  * @see enum TN_TaskState
621  */
622 enum TN_RCode tn_task_resume(struct TN_Task *task);
623 
624 /**
625  * Put current task to sleep for at most timeout ticks. When the timeout
626  * expires and the task was not suspended during the sleep, it is switched to
627  * runnable state. If the timeout value is `#TN_WAIT_INFINITE` and the task was
628  * not suspended during the sleep, the task will sleep until another function
629  * call (like `tn_task_wakeup()` or similar) will make it runnable.
630  *
631  * $(TN_CALL_FROM_TASK)
632  * $(TN_CAN_SWITCH_CONTEXT)
633  * $(TN_CAN_SLEEP)
634  * $(TN_LEGEND_LINK)
635  *
636  * @param timeout
637  * Refer to `#TN_TickCnt`
638  *
639  * @returns
640  * * `#TN_RC_TIMEOUT` if task has slept specified timeout;
641  * * `#TN_RC_OK` if task was woken up from other task by `tn_task_wakeup()`
642  * * `#TN_RC_FORCED` if task was released from wait forcibly by
643  * `tn_task_release_wait()`
644  * * `#TN_RC_WCONTEXT` if called from wrong context
645  *
646  * @see TN_TickCnt
647  */
648 enum TN_RCode tn_task_sleep(TN_TickCnt timeout);
649 
650 /**
651  * Wake up task from sleep.
652  *
653  * Task is woken up if only it sleeps because of call to `tn_task_sleep()`.
654  * If task sleeps for some another reason, task won't be woken up,
655  * and `tn_task_wakeup()` returns `#TN_RC_WSTATE`.
656  *
657  * After this call, `tn_task_sleep()` returns `#TN_RC_OK`.
658  *
659  * $(TN_CALL_FROM_TASK)
660  * $(TN_CAN_SWITCH_CONTEXT)
661  * $(TN_LEGEND_LINK)
662  *
663  * @param task sleeping task to wake up
664  *
665  * @return
666  * * `#TN_RC_OK` if successful
667  * * `#TN_RC_WSTATE` if task is not sleeping, or it is sleeping for
668  * some reason other than `tn_task_sleep()` call.
669  * * `#TN_RC_WCONTEXT` if called from wrong context;
670  * * If `#TN_CHECK_PARAM` is non-zero, additional return codes
671  * are available: `#TN_RC_WPARAM` and `#TN_RC_INVALID_OBJ`.
672  *
673  */
674 enum TN_RCode tn_task_wakeup(struct TN_Task *task);
675 
676 /**
677  * The same as `tn_task_wakeup()` but for using in the ISR.
678  *
679  * $(TN_CALL_FROM_ISR)
680  * $(TN_CAN_SWITCH_CONTEXT)
681  * $(TN_LEGEND_LINK)
682  */
683 enum TN_RCode tn_task_iwakeup(struct TN_Task *task);
684 
685 /**
686  * Activate task that is in $(TN_TASK_STATE_DORMANT) state, that is, it was
687  * either just created by `tn_task_create()` without
688  * `#TN_TASK_CREATE_OPT_START` option, or terminated.
689  *
690  * Task is moved from $(TN_TASK_STATE_DORMANT) state to the
691  * $(TN_TASK_STATE_RUNNABLE) state.
692  *
693  * $(TN_CALL_FROM_TASK)
694  * $(TN_CAN_SWITCH_CONTEXT)
695  * $(TN_LEGEND_LINK)
696  *
697  * @param task dormant task to activate
698  *
699  * @return
700  * * `#TN_RC_OK` if successful
701  * * `#TN_RC_WSTATE` if task is not dormant
702  * * `#TN_RC_WCONTEXT` if called from wrong context;
703  * * If `#TN_CHECK_PARAM` is non-zero, additional return codes
704  * are available: `#TN_RC_WPARAM` and `#TN_RC_INVALID_OBJ`.
705  *
706  * @see TN_TaskState
707  */
708 enum TN_RCode tn_task_activate(struct TN_Task *task);
709 
710 /**
711  * The same as `tn_task_activate()` but for using in the ISR.
712  *
713  * $(TN_CALL_FROM_ISR)
714  * $(TN_CAN_SWITCH_CONTEXT)
715  * $(TN_LEGEND_LINK)
716  */
717 enum TN_RCode tn_task_iactivate(struct TN_Task *task);
718 
719 /**
720  * Release task from $(TN_TASK_STATE_WAIT) state, independently of the reason
721  * of waiting.
722  *
723  * If task is in $(TN_TASK_STATE_WAIT) state, it is moved to
724  * $(TN_TASK_STATE_RUNNABLE) state. If task is in $(TN_TASK_STATE_WAITSUSP)
725  * state, it is moved to $(TN_TASK_STATE_SUSPEND) state.
726  *
727  * `#TN_RC_FORCED` is returned to the waiting task.
728  *
729  * $(TN_CALL_FROM_TASK)
730  * $(TN_CAN_SWITCH_CONTEXT)
731  * $(TN_LEGEND_LINK)
732  *
733  * \attention Usage of this function is discouraged, since the need for
734  * it indicates bad software design
735  *
736  * @param task task waiting for anything
737  *
738  * @return
739  * * `#TN_RC_OK` if successful
740  * * `#TN_RC_WSTATE` if task is not waiting for anything
741  * * `#TN_RC_WCONTEXT` if called from wrong context;
742  * * If `#TN_CHECK_PARAM` is non-zero, additional return codes
743  * are available: `#TN_RC_WPARAM` and `#TN_RC_INVALID_OBJ`.
744  *
745  *
746  * @see TN_TaskState
747  */
748 enum TN_RCode tn_task_release_wait(struct TN_Task *task);
749 
750 /**
751  * The same as `tn_task_release_wait()` but for using in the ISR.
752  *
753  * $(TN_CALL_FROM_ISR)
754  * $(TN_CAN_SWITCH_CONTEXT)
755  * $(TN_LEGEND_LINK)
756  */
757 enum TN_RCode tn_task_irelease_wait(struct TN_Task *task);
758 
759 /**
760  * This function terminates the currently running task. The task is moved to
761  * the $(TN_TASK_STATE_DORMANT) state.
762  *
763  * After exiting, the task may be either deleted by the `tn_task_delete()`
764  * function call or reactivated by the `tn_task_activate()` /
765  * `tn_task_iactivate()` function call. In this case task starts execution from
766  * beginning (as after creation/activation). The task will have the lowest
767  * precedence among all tasks with the same priority in the
768  * $(TN_TASK_STATE_RUNNABLE) state.
769  *
770  * If this function is invoked with `#TN_TASK_EXIT_OPT_DELETE` option set, the
771  * task will be deleted after termination and cannot be reactivated (needs
772  * recreation).
773  *
774  * Please note that returning from task body function has the same effect as
775  * calling `tn_task_exit(0)`.
776  *
777  * $(TN_CALL_FROM_TASK)
778  * $(TN_CAN_SWITCH_CONTEXT)
779  * $(TN_LEGEND_LINK)
780  *
781  * @return
782  * Returns if only called from wrong context. Normally, it never returns
783  * (since calling task becomes terminated)
784  *
785  * @see `#TN_TASK_EXIT_OPT_DELETE`
786  * @see `tn_task_delete()`
787  * @see `tn_task_activate()`
788  * @see `tn_task_iactivate()`
789  */
790 void tn_task_exit(enum TN_TaskExitOpt opts);
791 
792 
793 /**
794  * This function is similar to `tn_task_exit()` but it terminates any task
795  * other than currently running one.
796  *
797  * After task is terminated, the task may be either deleted by the
798  * `tn_task_delete()` function call or reactivated by the `tn_task_activate()`
799  * / `tn_task_iactivate()` function call. In this case task starts execution
800  * from beginning (as after creation/activation). The task will have the
801  * lowest precedence among all tasks with the same priority in the
802  * $(TN_TASK_STATE_RUNNABLE) state.
803  *
804  * $(TN_CALL_FROM_TASK)
805  * $(TN_CAN_SWITCH_CONTEXT)
806  * $(TN_LEGEND_LINK)
807  *
808  * @param task task to terminate
809  *
810  * @return
811  * * `#TN_RC_OK` if successful
812  * * `#TN_RC_WSTATE` if task is already dormant
813  * * `#TN_RC_WCONTEXT` if called from wrong context;
814  * * If `#TN_CHECK_PARAM` is non-zero, additional return codes
815  * are available: `#TN_RC_WPARAM` and `#TN_RC_INVALID_OBJ`.
816  */
817 enum TN_RCode tn_task_terminate(struct TN_Task *task);
818 
819 /**
820  * This function deletes the task specified by the task. The task must be in
821  * the $(TN_TASK_STATE_DORMANT) state, otherwise `#TN_RC_WCONTEXT` will be
822  * returned.
823  *
824  * This function resets the `id_task` field in the task structure to 0 and
825  * removes the task from the system tasks list. The task can not be reactivated
826  * after this function call (the task must be recreated).
827  *
828  * $(TN_CALL_FROM_TASK)
829  * $(TN_LEGEND_LINK)
830  *
831  * @param task dormant task to delete
832  *
833  * @return
834  * * `#TN_RC_OK` if successful
835  * * `#TN_RC_WSTATE` if task is not dormant
836  * * `#TN_RC_WCONTEXT` if called from wrong context;
837  * * If `#TN_CHECK_PARAM` is non-zero, additional return codes
838  * are available: `#TN_RC_WPARAM` and `#TN_RC_INVALID_OBJ`.
839  *
840  */
841 enum TN_RCode tn_task_delete(struct TN_Task *task);
842 
843 /**
844  * Get current state of the task; note that returned state is a bitmask,
845  * that is, states could be combined with each other.
846  *
847  * Currently, only $(TN_TASK_STATE_WAIT) and $(TN_TASK_STATE_SUSPEND) states
848  * are allowed to be set together. Nevertheless, it would be probably good
849  * idea to test individual bits in the returned value instead of plain
850  * comparing values.
851  *
852  * Note that if something goes wrong, variable pointed to by `p_state`
853  * isn't touched.
854  *
855  * $(TN_CALL_FROM_TASK)
856  * $(TN_LEGEND_LINK)
857  *
858  * @param task
859  * task to get state of
860  * @param p_state
861  * pointer to the location where to store state of the task
862  *
863  * @return state of the task
864  */
866  struct TN_Task *task,
867  enum TN_TaskState *p_state
868  );
869 
870 #if TN_PROFILER || DOXYGEN_ACTIVE
871 /**
872  * Read profiler timing data of the task. See `struct #TN_TaskTiming` for
873  * details on timing data.
874  *
875  * $(TN_CALL_FROM_TASK)
876  * $(TN_CALL_FROM_ISR)
877  * $(TN_LEGEND_LINK)
878  *
879  * @param task
880  * Task to get timing data of
881  * @param tgt
882  * Target structure to fill with data, should be allocated by caller
883  */
885  const struct TN_Task *task,
886  struct TN_TaskTiming *tgt
887  );
888 #endif
889 
890 
891 /**
892  * Set new priority for task.
893  * If priority is 0, then task's base_priority is set.
894  *
895  * $(TN_CALL_FROM_TASK)
896  * $(TN_LEGEND_LINK)
897  *
898  * \attention this function is obsolete and will probably be removed
899  */
900 enum TN_RCode tn_task_change_priority(struct TN_Task *task, int new_priority);
901 
902 #ifdef __cplusplus
903 } /* extern "C" */
904 #endif
905 
906 #endif // _TN_TASKS_H
907 
908 
909 /*******************************************************************************
910  * end of file
911  ******************************************************************************/
912 
913 
enum TN_RCode tn_task_activate(struct TN_Task *task)
Activate task that is in DORMANT state, that is, it was either just created by tn_task_create() witho...
TN_WaitReason
Task wait reason.
Definition: tn_tasks.h:173
Task wants to lock a mutex with priority inheritance.
Definition: tn_tasks.h:205
const char * name
Task name for debug purposes, user may want to set it by hand.
Definition: tn_tasks.h:432
enum TN_RCode tn_task_release_wait(struct TN_Task *task)
Release task from WAIT state, independently of the reason of waiting.
enum TN_RCode tn_task_iwakeup(struct TN_Task *task)
The same as tn_task_wakeup() but for using in the ISR.
enum TN_RCode tn_task_terminate(struct TN_Task *task)
This function is similar to tn_task_exit() but it terminates any task other than currently running on...
Internal kernel structure for profiling data of task.
Definition: tn_tasks.h:302
Circular doubly linked list, for internal kernel usage.
Task is suspended (by some other task)
Definition: tn_tasks.h:158
enum TN_RCode tn_task_create(struct TN_Task *task, TN_TaskBody *task_func, int priority, TN_UWord *task_stack_low_addr, int task_stack_size, void *param, enum TN_TaskCreateOpt opts)
Construct task and probably start it (depends on options, see below).
enum TN_WaitReason last_wait_reason
Available if only TN_PROFILER_WAIT_TIME option is non-zero.
Definition: tn_tasks.h:311
enum TN_RCode tn_task_profiler_timing_get(const struct TN_Task *task, struct TN_TaskTiming *tgt)
Read profiler timing data of the task.
unsigned long max_consecutive_run_time
Maximum consecutive time task was running.
Definition: tn_tasks.h:270
Task.
Definition: tn_tasks.h:330
TN_RCode
Result code returned by kernel services.
Definition: tn_common.h:81
DQueue-specific fields related to waiting task, to be included in struct TN_Task. ...
Definition: tn_dqueue.h:142
TN_ObjId
Magic number for object validity verification.
Definition: tn_common.h:65
EventGrp-specific fields related to waiting task, to be included in struct TN_Task.
Definition: tn_eventgrp.h:236
unsigned long TN_TickCnt
Type for system tick count, it is used by the kernel to represent absolute tick count value as well a...
Definition: tn_common.h:188
enum TN_WaitReason task_wait_reason
reason for waiting (relevant if only task_state is WAIT or WAIT+SUSPEND)
Definition: tn_tasks.h:399
unsigned long long total_wait_time[TN_WAIT_REASONS_CNT]
Available if only TN_PROFILER_WAIT_TIME option is non-zero.
Definition: tn_tasks.h:285
Task was previously waiting, and after this it was suspended.
Definition: tn_tasks.h:161
Task wants to receive some data to the data queue, and there's no data in the queue.
Definition: tn_tasks.h:197
Definitions used through the whole kernel.
TN_UWord * stack_cur_pt
pointer to task's current top of the stack; Note that this field must be a first field in the struct...
Definition: tn_tasks.h:334
enum TN_TaskState task_state
task state
Definition: tn_tasks.h:395
unsigned long max_consecutive_wait_time[TN_WAIT_REASONS_CNT]
Available if only TN_PROFILER_WAIT_TIME option is non-zero.
Definition: tn_tasks.h:293
enum TN_RCode tn_task_delete(struct TN_Task *task)
This function deletes the task specified by the task.
for internal kernel usage only: this option must be provided when creating idle task ...
Definition: tn_tasks.h:230
Task is waiting.
Definition: tn_tasks.h:155
TN_TaskCreateOpt
Options for tn_task_create()
Definition: tn_tasks.h:221
struct TN_EGrpTaskWait eventgrp
fields specific to tn_eventgrp.h
Definition: tn_tasks.h:422
TN_TickCnt last_tick_cnt
Tick count of when the task got running or non-running last time.
Definition: tn_tasks.h:305
TN_TaskBody * task_func_addr
pointer to task's body function given to tn_task_create()
Definition: tn_tasks.h:382
int tslice_count
time slice counter
Definition: tn_tasks.h:408
enum TN_RCode tn_task_change_priority(struct TN_Task *task, int new_priority)
Set new priority for task.
struct TN_ListItem deadlock_list
list of other tasks involved in deadlock.
Definition: tn_tasks.h:368
Timer is a kernel object that is used to ask the kernel to call some user-provided function at a part...
enum TN_RCode tn_task_wakeup(struct TN_Task *task)
Wake up task from sleep.
enum TN_RCode tn_task_sleep(TN_TickCnt timeout)
Put current task to sleep for at most timeout ticks.
union TN_Task::@2 subsys_wait
subsystem-specific fields that are used while task waits for something.
TN_TaskState
Task state.
Definition: tn_tasks.h:141
This state should never be publicly available.
Definition: tn_tasks.h:146
Timer.
Definition: tn_timer.h:205
Fixed memory blocks pool.
enum TN_RCode tn_task_suspend(struct TN_Task *task)
If the task is RUNNABLE, it is moved to the SUSPEND state.
Timing structure that is managed by profiler and can be read by tn_task_profiler_timing_get() functio...
Definition: tn_tasks.h:254
void tn_task_exit(enum TN_TaskExitOpt opts)
This function terminates the currently running task.
whether task should be deleted right after it is exited.
Definition: tn_tasks.h:242
enum TN_RCode tn_task_irelease_wait(struct TN_Task *task)
The same as tn_task_release_wait() but for using in the ISR.
enum TN_RCode tn_task_resume(struct TN_Task *task)
Release task from SUSPEND state.
int base_priority
base priority of the task (actual current priority may be higher than base priority because of mutex)...
Definition: tn_tasks.h:389
Event group.
Task isn't yet activated or it was terminated by tn_task_terminate().
Definition: tn_tasks.h:164
Task has called tn_task_sleep()
Definition: tn_tasks.h:179
int is_running
For internal profiler self-check only: indicates whether task is running or not.
Definition: tn_tasks.h:318
TN_UWord * stack_high_addr
– Highest address of stack.
Definition: tn_tasks.h:379
enum TN_ObjId id_task
id for object validity verification.
Definition: tn_tasks.h:341
Task is ready to run (it doesn't mean that it is running at the moment)
Definition: tn_tasks.h:149
Task wants to get memory block from memory pool, and there's no free memory blocks.
Definition: tn_tasks.h:210
struct TN_DQueueTaskWait dqueue
fields specific to tn_dqueue.h
Definition: tn_tasks.h:425
unsigned waited
Flag indicates that task waited for something This flag is set automatially in _tn_task_set_waiting()...
Definition: tn_tasks.h:447
int priority
current task priority
Definition: tn_tasks.h:392
struct _TN_TaskProfiler profiler
Profiler data, available if only TN_PROFILER is non-zero.
Definition: tn_tasks.h:435
enum TN_RCode tn_task_iactivate(struct TN_Task *task)
The same as tn_task_activate() but for using in the ISR.
struct TN_ListItem * pwait_queue
pointer to object's (semaphore, mutex, event, etc) wait list in which task is included for waiting ...
Definition: tn_tasks.h:351
struct TN_ListItem task_queue
queue is used to include task in ready/wait lists
Definition: tn_tasks.h:344
Task wants to lock a mutex with priority ceiling.
Definition: tn_tasks.h:201
struct TN_FMemTaskWait fmem
fields specific to tn_fmem.h
Definition: tn_tasks.h:428
struct TN_Timer timer
timer object to implement task waiting for timeout
Definition: tn_tasks.h:347
struct TN_TaskTiming timing
Main timing structure managed by profiler.
Definition: tn_tasks.h:323
Kernel system routines: system start, tick processing, time slice managing.
unsigned long long got_running_cnt
How many times task got running.
Definition: tn_tasks.h:267
Task wants to put some data to the data queue, and there's no space in the queue. ...
Definition: tn_tasks.h:192
enum TN_RCode tn_task_state_get(struct TN_Task *task, enum TN_TaskState *p_state)
Get current state of the task; note that returned state is a bitmask, that is, states could be combin...
void( TN_TaskBody)(void *param)
Prototype for task body function.
Definition: tn_common.h:145
Task waits to acquire a semaphore.
Definition: tn_tasks.h:183
Task isn't waiting for anything.
Definition: tn_tasks.h:176
unsigned priority_already_updated
Internal flag used to optimize mutex priority algorithms.
Definition: tn_tasks.h:441
whether task should be activated right after it is created.
Definition: tn_tasks.h:226
void * task_func_param
pointer to task's parameter given to tn_task_create()
Definition: tn_tasks.h:385
FMem-specific fields related to waiting task, to be included in struct TN_Task.
Definition: tn_fmem.h:118
unsigned long long total_run_time
Total time when task was running.
Definition: tn_tasks.h:263
Wait reasons count.
Definition: tn_tasks.h:215
Circular doubly linked list item, for internal kernel usage.
Definition: tn_list.h:63
unsigned int TN_UWord
Unsigned integer type whose size is equal to the size of CPU register.
TN_UWord * stack_low_addr
– lowest address of stack.
Definition: tn_tasks.h:375
enum TN_RCode tn_task_create_wname(struct TN_Task *task, TN_TaskBody *task_func, int priority, TN_UWord *task_stack_low_addr, int task_stack_size, void *param, enum TN_TaskCreateOpt opts, const char *name)
The same as tn_task_create() but with additional argument name, which could be very useful for debug...
Task waits for some event in the event group to be set.
Definition: tn_tasks.h:187
A data queue is a FIFO that stores pointer (of type void *) in each cell, called (in uITRON style) a ...
struct TN_ListItem create_queue
queue is used to include task in creation list (currently, this list is used for statistics only) ...
Definition: tn_tasks.h:355
TN_TaskExitOpt
Options for tn_task_exit()
Definition: tn_tasks.h:236
enum TN_RCode task_wait_rc
waiting result code (reason why waiting finished)
Definition: tn_tasks.h:402
struct TN_ListItem mutex_queue
list of all mutexes that are locked by task
Definition: tn_tasks.h:360