1 2 3 4 5 6 7 8 9
10 11 12 13
14
15 package ti.sysbios.knl;
16
17 import xdc.rov.ViewInfo;
18
19 import xdc.runtime.Error;
20 import xdc.runtime.Assert;
21 import xdc.runtime.Diags;
22 import xdc.runtime.Log;
23 import xdc.runtime.IHeap;
24
25 import ti.sysbios.misc.Queue;
26
27 /*!
28 * ======== Task ========
29 * Task Manager.
30 *
31 * The Task module makes available a set of functions that manipulate task
32 * objects accessed through pointers of type {@link #Handle}. Tasks represent
33 * independent threads of control that conceptually execute functions in
34 * parallel within a single C program; in reality, concurrency is achieved
35 * by switching the processor from one task to another.
36 *
37 * When you create a task, it is provided with its own run-time stack,
38 * used for storing local variables as well as for further nesting of
39 * function calls. Each stack must be large enough to handle normal
40 * subroutine calls and one task preemption context.
41 * A task preemption context is the context that gets saved when one task
42 * preempts another as a result of an interrupt thread readying
43 * a higher-priority task.
44 *
45 * All tasks executing within a single program share a common set of
46 * global variables, accessed according to the standard rules of scope
47 * defined for C functions.
48 *
49 * Each task is in one of five modes of execution at any point in time:
50 * running, ready, blocked, terminated, or inactive. By design, there is
51 * always one
52 * (and only one) task currently running, even if it is only the idle task
53 * managed internally by Task. The current task can be suspended from
54 * execution by calling certain Task functions, as well as functions
55 * provided by other modules like the Semaphore or Event Modules.
56 * The current task
57 * can also terminate its own execution. In either case, the processor
58 * is switched to the highest priority task that is ready to run.
59 *
60 * You can assign numeric priorities to tasks. Tasks are
61 * readied for execution in strict priority order; tasks of the same
62 * priority are scheduled on a first-come, first-served basis.
63 * The priority of the currently running task is never lower
64 * than the priority of any ready task. Conversely, the running task
65 * is preempted and re-scheduled for execution whenever there exists
66 * some ready task of higher priority.
67 *
68 * Stack alignment
69 *
70 * Stack size parameters for both static and dynamic tasks are rounded
71 * up to the nearest integer multiple of a target specific alignment
72 * requirement.
73 *
74 * In the case of Task's which are created with a user-provided stack,
75 * both the base address and the stackSize are aligned. The base address
76 * is increased to the nearest aligned address. The stack size is decreased
77 * accordingly and then rounded down to the nearest integer multiple of the
78 * target-specific required alignment.
79 *
80 * Hook Functions
81 *
82 * Sets of hook functions can be specified for the Task module. Each
83 * set constains these hook functions:
84 * @p(blist)
85 * -Register: A function called before any statically created tasks
86 * are initialized at runtime. The register hook is called at boot time
87 * before main() and before interrupts are enabled.
88 * -Create: A function that is called when a task is created.
89 * This includes tasks that are created statically and those
90 * created dynamically using {@link #create} or {@link #construct}.
91 * The create hook is called outside of a Task_disable/enable block and
92 * before the task has been added to the ready list.
93 * -Ready: A function that is called when a task becomes ready to run.
94 * The ready hook is called from within a Task_disable/enable block with
95 * interrupts enabled.
96 * -Switch: A function that is called just before a task switch
97 * occurs. The 'prev' and 'next' task handles are passed to the Switch
98 * hook. 'prev' is set to NULL for the initial task switch that occurs
99 * during BIOS startup. The Switch hook is called from within a
100 * Task_disable/enable block with interrupts enabled.
101 * -Exit: A function that is called when a task exits using
102 * {@link #exit}. The exit hook is passed the handle of the exiting
103 * task. The exit hook is called outside of a Task_disable/enable block
104 * and before the task has been removed from the kernel lists.
105 * -Delete: A function that is called when any task is deleted at
106 * run-time with {@link #delete}. The delete hook is called outside
107 * of a Task_disable/enable block.
108 * @p
109 * Hook functions can only be configured statically.
110 *
111 * Register Function
112 *
113 * The Register function is provided to allow a hook set to store its
114 * hookset ID. This id can be passed to {@link #setHookContext} and
115 * {@link #getHookContext} to set or get hookset-specific context. The
116 * Register function must be specified if the hook implementation
117 * needs to use {@link #setHookContext} or {@link #getHookContext}.
118 * The registerFxn hook function is called during system initialization
119 * before interrupts have been enabled.
120 *
121 * @p(code)
122 * Void myRegisterFxn(Int id);
123 * @p
124 *
125 * Create and Delete Functions
126 *
127 * The create and delete functions are called whenever a Task is created
128 * or deleted. They are called with interrupts enabled (unless called
129 * at boot time or from main()).
130 *
131 * @p(code)
132 * Void myCreateFxn(Task_Handle task, Error_Block *eb);
133 * @p
134 *
135 * @p(code)
136 * Void myDeleteFxn(Task_Handle task);
137 * @p
138 *
139 * Switch Function
140 *
141 * If a switch function is specified, it is invoked just before the new task
142 * is switched to. The switch function is called with interrupts enabled.
143 *
144 * This function can be used to save/restore additional task context (for
145 * example, external hardware registers), to check for task stack overflow,
146 * to monitor the time used by each task, etc.
147 *
148 * @p(code)
149 * Void mySwitchFxn(Task_Handle prev, Task_Handle next);
150 * @p
151 *
152 * Ready Function
153 *
154 * If a ready function is specified, it is invoked whenever a task is made
155 * ready to run. The ready function is called with interrupts enabled
156 * (unless called at boot time or from main()).
157 *
158 * @p(code)
159 * Void myReadyFxn(Task_Handle task);
160 * @p
161 *
162 * Exit Function
163 *
164 * If an exit function is specified, it is invoked when a task exits (via
165 * call to Task_exit() or when a task returns from its' main function).
166 * The Exit Function is called with interrupts enabled.
167 *
168 * @p(code)
169 * Void myExitFxn(Task_Handle task);
170 * @p
171 *
172 * @p(html)
173 * <h3> Calling Context </h3>
174 * <table border="1" cellpadding="3">
175 * <colgroup span="1"></colgroup> <colgroup span="5" align="center"></colgroup>
176 *
177 * <tr><th> Function </th><th> Hwi </th><th> Swi </th><th> Task </th><th> Main </th><th> Startup </th></tr>
178 * <!-- -->
179 * <tr><td> {@link #create} </td><td> N </td><td> N </td><td> Y </td><td> Y </td><td> N </td></tr>
180 * <tr><td> {@link #disable} </td><td> Y </td><td> Y </td><td> Y </td><td> Y </td><td> N </td></tr>
181 * <tr><td> {@link #exit} </td><td> N </td><td> N </td><td> Y </td><td> N </td><td> N </td></tr>
182 * <tr><td> {@link #getIdleTask} </td><td> Y </td><td> Y </td><td> Y </td><td> Y </td><td> N </td></tr>
183 * <tr><td> {@link #Params_init} </td><td> Y </td><td> Y </td><td> Y </td><td> Y </td><td> Y </td></tr>
184 * <tr><td> {@link #restore} </td><td> Y </td><td> Y </td><td> Y </td><td> Y </td><td> N </td></tr>
185 * <tr><td> {@link #self} </td><td> Y </td><td> Y </td><td> Y </td><td> Y </td><td> N </td></tr>
186 * <tr><td> {@link #sleep} </td><td> N </td><td> N </td><td> Y </td><td> N </td><td> N </td></tr>
187 * <tr><td> {@link #yield} </td><td> Y </td><td> Y </td><td> Y </td><td> N </td><td> N </td></tr>
188 *
189 * <tr><td> {@link #construct} </td><td> N </td><td> N </td><td> Y </td><td> Y </td><td> N </td></tr>
190 * <tr><td> {@link #delete} </td><td> N </td><td> N </td><td> Y </td><td> Y </td><td> N </td></tr>
191 * <tr><td> {@link #destruct} </td><td> N </td><td> N </td><td> Y </td><td> Y </td><td> N </td></tr>
192 * <tr><td> {@link #getEnv} </td><td> Y </td><td> Y </td><td> Y </td><td> Y </td><td> N </td></tr>
193 * <tr><td> {@link #getHookContext} </td><td> Y </td><td> Y </td><td> Y </td><td> Y </td><td> N </td></tr>
194 * <tr><td> {@link #getMode} </td><td> Y </td><td> Y </td><td> Y </td><td> Y </td><td> N </td></tr>
195 * <tr><td> {@link #getPri} </td><td> Y </td><td> Y </td><td> Y </td><td> Y </td><td> N </td></tr>
196 * <tr><td> {@link #setEnv} </td><td> Y </td><td> Y </td><td> Y </td><td> Y </td><td> N </td></tr>
197 * <tr><td> {@link #setHookContext} </td><td> Y </td><td> Y </td><td> Y </td><td> Y </td><td> N </td></tr>
198 * <tr><td> {@link #setPri} </td><td> Y </td><td> Y </td><td> Y </td><td> N </td><td> N </td></tr>
199 * <tr><td> {@link #stat} </td><td> Y </td><td> Y </td><td> Y </td><td> Y </td><td> N </td></tr>
200 * <tr><td colspan="6"> Definitions: <br />
201 * <ul>
202 * <li> <b>Hwi</b>: API is callable from a Hwi thread. </li>
203 * <li> <b>Swi</b>: API is callable from a Swi thread. </li>
204 * <li> <b>Task</b>: API is callable from a Task thread. </li>
205 * <li> <b>Main</b>: API is callable during any of these phases: </li>
206 * <ul>
207 * <li> In your module startup after this module is started (e.g. Task_Module_startupDone() returns TRUE). </li>
208 * <li> During xdc.runtime.Startup.lastFxns. </li>
209 * <li> During main().</li>
210 * <li> During BIOS.startupFxns.</li>
211 * </ul>
212 * <li> <b>Startup</b>: API is callable during any of these phases:</li>
213 * <ul>
214 * <li> During xdc.runtime.Startup.firstFxns.</li>
215 * <li> In your module startup before this module is started (e.g. Task_Module_startupDone() returns FALSE).</li>
216 * </ul>
217 * </ul>
218 * </td></tr>
219 *
220 * </table>
221 * @p
222 */
223
224 @ModuleStartup
225 @InstanceFinalize
226 @InstanceInitError
227
228 module Task
229 {
230
231
232
233
234
235 /*! Task function type definition. */
236 typedef Void (*FuncPtr)(UArg, UArg);
237
238 /*!
239 * Task execution modes.
240 *
241 * These enumerations are the range of modes or states that
242 * a task can be in. A task's current mode can be gotten using
243 * {@link #stat}.
244 */
245 enum Mode {
246 Mode_RUNNING, /*! Task is currently executing. */
247 Mode_READY, /*! Task is scheduled for execution. */
248 Mode_BLOCKED, /*! Task is suspended from execution. */
249 Mode_TERMINATED, /*! Task is terminated from execution. */
250 Mode_INACTIVE /*! Task is on inactive task list */
251 };
252
253 /*!
254 * Task Status Buffer.
255 *
256 * Passed to and filled in by {@link #stat};
257 */
258 struct Stat {
259 Int priority; /*! Task priority. */
260 Ptr stack; /*! Task stack. */
261 SizeT stackSize; /*! Task stack size. */
262 IHeap.Handle stackHeap; /*! Heap used to alloc stack. */
263 Ptr env; /*! Global environment struct. */
264 Mode mode; /*! Task's current mode. */
265 Ptr sp; /*! Task's current stack pointer. */
266 SizeT used; /*! max # of words used on stack. */
267 };
268
269 /*! Task hook set type definition. */
270 struct HookSet {
271 Void (*registerFxn)(Int);
272 Void (*createFxn)(Handle, Error.Block *);
273 Void (*readyFxn)(Handle);
274 Void (*switchFxn)(Handle, Handle);
275 Void (*exitFxn)(Handle);
276 Void (*deleteFxn)(Handle);
277 };
278
279 metaonly struct BasicView {
280 String label;
281 Int priority;
282 String mode;
283 String fxn[];
284 UArg arg0;
285 UArg arg1;
286 SizeT stackSize;
287 Ptr stackBase;
288 }
289
290 metaonly struct DetailedView {
291 String label;
292 Int priority;
293 String mode;
294 String fxn[];
295 UArg arg0;
296 UArg arg1;
297 SizeT stackPeak;
298 SizeT stackSize;
299 Ptr stackBase;
300 String blockedOn;
301 }
302
303 metaonly struct ModuleView {
304 String schedulerState;
305 String readyQMask;
306 Bool workPending;
307 UInt numVitalTasks;
308 Ptr currentTask;
309 SizeT hwiStackPeak;
310 SizeT hwiStackSize;
311 Ptr hwiStackBase;
312 }
313
314 /*! @_nodoc */
315 @Facet
316 metaonly config ViewInfo.Instance rovViewInfo =
317 ViewInfo.create({
318 viewMap: [
319 ['Basic', {type: ViewInfo.INSTANCE, viewInitFxn: 'viewInitBasic', structName: 'BasicView'}],
320 ['Detailed', {type: ViewInfo.INSTANCE, viewInitFxn: 'viewInitDetailed', structName: 'DetailedView'}],
321 ['Module', {type: ViewInfo.MODULE, viewInitFxn: 'viewInitModule', structName: 'ModuleView'}],
322 ]
323 });
324
325
326
327
328
329 /*! Logged on every task switch */
330 config Log.Event LM_switch = {
331 mask: Diags.USER1 | Diags.USER2,
332 msg: "LM_switch: oldtsk: 0x%x, oldfunc: 0x%x, newtsk: 0x%x, newfunc: 0x%x"
333 };
334
335 /*! Logged on calls to Task_sleep */
336 config Log.Event LM_sleep = {
337 mask: Diags.USER1 | Diags.USER2,
338 msg: "LM_sleep: tsk: 0x%x, func: 0x%x, timeout: %d"
339 };
340
341 /*! Logged when a task is made ready to run (ie Semaphore_post()) */
342 config Log.Event LD_ready = {
343 mask: Diags.USER2,
344 msg: "LD_ready: tsk: 0x%x, func: 0x%x, pri: %d"
345 };
346
347 /*! Logged when a task is blocked (ie Semaphore_pend()) */
348 config Log.Event LD_block = {
349 mask: Diags.USER2,
350 msg: "LD_block: tsk: 0x%x, func: 0x%x"
351 };
352
353 /*! Logged on calls to Task_yield */
354 config Log.Event LM_yield = {
355 mask: Diags.USER1 | Diags.USER2,
356 msg: "LM_yield: tsk: 0x%x, func: 0x%x, currThread: %d"
357 };
358
359 /*! Logged on calls to Task_setPri */
360 config Log.Event LM_setPri = {
361 mask: Diags.USER1 | Diags.USER2,
362 msg: "LM_setPri: tsk: 0x%x, func: 0x%x, oldPri: %d, newPri %d"
363 };
364
365 /*!
366 * Logged when Task functions fall thru the bottom
367 * or when Task_exit() is explicitly called.
368 */
369 config Log.Event LD_exit = {
370 mask: Diags.USER2,
371 msg: "LD_exit: tsk: 0x%x, func: 0x%x"
372 };
373
374
375
376 /*!
377 * Error raised when a stack overflow (or corruption) is detected.
378 *
379 * This error is raised by kernel's stack checking function. This
380 * function checks the stacks before every task switch to make sure
381 * that reserved word at top of stack has not been modified.
382 *
383 * The stack checking logic is enabled by the {@link #initStackFlag} and
384 * {@link #checkStackFlag} configuration parameters. If both of these
385 * flags are set to true, the kernel will validate the stacks.
386 */
387 config Error.Id E_stackOverflow = {
388 msg: "E_stackOverflow: Task '%s' stack overflow."
389 };
390
391
392
393 /*!
394 * Assert if all tasks are blocked.
395 *
396 * This can only happen if the
397 * idle task blocks (via I/O call, call to Semaphore_pend(), etc.).
398 * This should never happen since the idle task should never block.
399 */
400 config Assert.Id A_allBlocked = {
401 msg: "A_allBlocked: All tasks blocked."
402 };
403
404 /*! Asserted in Task_create and Task_delete */
405 config Assert.Id A_badThreadType = {
406 msg: "A_badThreadType: Cannot create/delete a task from Hwi or Swi thread."
407 };
408
409 /*! Asserted in Task_delete */
410 config Assert.Id A_badTaskState = {
411 msg: "A_badTaskState: Can't delete a task in BLOCKED or RUNNING state."
412 };
413
414 /*! Asserted in Task_create */
415 config Assert.Id A_taskDisabled = {
416 msg: "A_taskDisabled: Cannot create a task when tasking is disabled."
417 };
418
419 /*! Asserted in Task_create */
420 config Assert.Id A_badPriority = {
421 msg: "A_badPriority: An invalid task priority was used."
422 };
423
424 /*! Asserted in Task_sleep */
425 config Assert.Id A_badTimeout = {
426 msg: "A_badTimeout: Can't sleep FOREVER."
427 };
428
429 /*!
430 * Number of Task priorities supported. Default is 16.
431 *
432 * The maximum number of priorities supported is
433 * target specific and depends on the number of
434 * bits in a UInt data type. For 6x and Arm devices
435 * the maximum number of priorities is therefore 32.
436 * For 28x and 55x devices, the maximum number of
437 * priorities is 16.
438 */
439 config UInt numPriorities = 16;
440
441 /*!
442 * Default stack size (in MAUs) used for all tasks.
443 *
444 * Default is obtained from the target-specific Task_Support module.
445 */
446 config SizeT defaultStackSize;
447
448 /*!
449 * Default memory section used for all statically created task stacks.
450 *
451 * The default stack section name is ".taskStackSection" which gets placed
452 * into the platform's stackMemory (ie Program.platform.stackMemory).
453 *
454 * To place all task stacks into a different memory segment,
455 * add the following to your config script:
456 *
457 * @p(code)
458 * Program.sectMap[Task.defaultStackSection] = new Program.SectionSpec();
459 * Program.sectMap[Task.defaultStackSection].loadSegment = "yourMemorySegment";
460 * @p
461 *
462 * To place all task stacks into a different section AND memory segment,
463 * add the following to your config script:
464 *
465 * @p(code)
466 * Task.defaultStackSection = ".yourSectionName";
467 * Program.sectMap[Task.defaultStackSection] = new Program.SectionSpec();
468 * Program.sectMap[Task.defaultStackSection].loadSegment = "yourMemorySegment";
469 * @p
470 *
471 * Where "yourSectionName" can be just about anything, and "yourMemorySegment"
472 * must be a memory segment defined within the
473 * {@link xdc.cfg.Program#platform Program.platform}
474 * the application is being built for.
475 */
476 metaonly config String defaultStackSection = ".taskStackSection";
477
478 /*!
479 * Default Mem heap used for all dynamically created task stacks.
480 *
481 * Default is null.
482 */
483 config IHeap.Handle defaultStackHeap;
484
485 /*!
486 * Idle task stack size in MAUs.
487 *
488 * Default is inherited from module config defaultStackSize.
489 */
490 metaonly config SizeT idleTaskStackSize;
491
492 /*!
493 * Idle task stack section
494 *
495 * Default is inherited from module config defaultStackSection;
496 */
497 metaonly config String idleTaskStackSection;
498
499 /*!
500 * Idle task's vitalTaskFlag.
501 * (see {@link #vitalTaskFlag}).
502 *
503 * Default is true.
504 */
505 metaonly config Bool idleTaskVitalTaskFlag = true;
506
507 /*!
508 * Initialize stack with known value for stack checking at runtime
509 * (see {@link #checkStackFlag}).
510 *
511 * This is also useful for inspection of stack in debugger or core
512 * dump utilities.
513 * Default is true.
514 */
515 config Bool initStackFlag = true;
516
517 /*!
518 * Check 'from' and 'to' task stacks before task context switch.
519 *
520 * The check consists of testing the top of stack value against
521 * its initial value (see {@link #initStackFlag}). If it is no
522 * longer at this value, the assumption is that the task has
523 * overrun its stack. If the test fails, then the
524 * {@link #E_stackOverflow} error is raised.
525 *
526 * Runtime stack checking is only performed if {@link #initStackFlag} is
527 * also true.
528 *
529 * Default is true.
530 */
531 metaonly config Bool checkStackFlag = true;
532
533 /*!
534 * const array that holds the HookSet objects.
535 */
536 config HookSet hooks[length] = [];
537
538
539
540 /*!
541 * ======== addHookSet ========
542 * addHookSet is used in a config file to add a hook set (defined
543 * by struct HookSet).
544 *
545 * HookSet structure elements may be omitted, in which case those
546 * elements will not exist.
547 *
548 * @param(hook) structure of type HookSet
549 */
550 metaonly Void addHookSet(HookSet hook);
551
552 /*!
553 * @_nodoc
554 * ======== Task_startup ========
555 * Start the task scheduler.
556 *
557 * Task_startup signals the end of boot operations, enables
558 * the Task scheduler and schedules the highest priority ready
559 * task for execution.
560 *
561 * Task_startup is called by BIOS_start() after Hwi_enable()
562 * and Swi_enable(). There is no return from this function as the
563 * execution thread is handed to the highest priority ready task.
564 */
565 Void startup();
566
567 /*!
568 * ======== Task_disable ========
569 * Disable the task scheduler.
570 *
571 * {@link #disable} and {@link #restore} control Task scheduling.
572 * {@link #disable} disables all other Tasks from running until
573 * {@link #restore} is called. Hardware and Software interrupts
574 * can still run.
575 *
576 * {@link #disable} and {@link #restore} allow you to ensure that
577 * statements
578 * that must be performed together during critical processing are not
579 * preempted by other Tasks.
580 *
581 * The value of the key returned is opaque to applications and is meant
582 * to be passed to Task_restore().
583 *
584 * In the following example, the critical section is
585 * not preempted by any Tasks.
586 *
587 * @p(code)
588 * key = Task_disable();
589 * `critical section`
590 * Task_restore(key);
591 * @p
592 *
593 * You can also use {@link #disable} and {@link #restore} to
594 * create several Tasks and allow them to be invoked in
595 * priority order.
596 *
597 * {@link #disable} calls can be nested.
598 *
599 * @b(returns) key for use with {@link #restore}
600 *
601 * @a(constraints)
602 * Do not call any function that can cause the current task to block
603 * within a {@link #disable}/{@link #restore} block. For example,
604 * {@link ti.sysbios.ipc.Semaphore#pend Semaphore_pend}
605 * (if timeout is non-zero),
606 * {@link #sleep}, {@link #yield}, and Memory_alloc can all
607 * cause blocking.
608 */
609 UInt disable();
610
611 /*!
612 * @_nodoc
613 * ======== enable ========
614 * Enable the task scheduler.
615 *
616 * {@link #enable} unconditionally enables the Task scheduler and
617 * schedules the highest priority ready task for execution.
618 *
619 * This function is called by {@link #startup} (which is called by
620 * {@link ti.sysbios.BIOS#start BIOS_start}) to begin multi-tasking
621 * operations.
622 */
623 Void enable();
624
625 /*!
626 * ======== restore ========
627 * Restore Task scheduling state.
628 *
629 * {@link #disable} and {@link #restore} control Task scheduling
630 * {@link #disable} disables all other Tasks from running until
631 * {@link #restore} is called. Hardware and Software interrupts
632 * can still run.
633 *
634 * {@link #disable} and {@link #restore} allow you to ensure that statements
635 * that must be performed together during critical processing are not
636 * preempted.
637
638 * In the following example, the critical section is not preempted
639 * by any Tasks.
640 *
641 * @p(code)
642 * key = Task_disable();
643 * `critical section`
644 * Task_restore(key);
645 * @p
646 *
647 * You can also use {@link #disable} and {@link #restore} to create
648 * several Tasks and allow them to be performed in priority order.
649 *
650 * {@link #disable} calls can be nested.
651 *
652 * {@link #restore} returns with interrupts enabled if the key unlocks
653 * the scheduler
654 *
655 * @param(key) key to restore previous Task scheduler state
656 *
657 * @a(constraints)
658 * Do not call any function that can cause the current task to block
659 * within a {@link #disable}/{@link #restore} block. For example,
660 * {@link ti.sysbios.ipc.Semaphore#pend Semaphore_pend()}
661 * (if timeout is non-zero),
662 * {@link #sleep}, {@link #yield}, and Memory_alloc can all
663 * cause blocking.
664 *
665 * {@link #restore} internally calls Hwi_enable() if the key passed
666 * to it results in the unlocking of the Task scheduler (ie if this
667 * is root Task_disable/Task_restore pair).
668 */
669 Void restore(UInt key);
670
671 /*!
672 * @_nodoc
673 * ======== restoreHwi ========
674 * Restore Task scheduling state.
675 * Used by dispatcher. Does not re-enable Ints.
676 */
677 Void restoreHwi(UInt key);
678
679 /*!
680 * ======== self ========
681 * Returns a handle to the currently executing Task object.
682 *
683 * Task_self returns the object handle for the currently executing task.
684 * This function is useful when inspecting the object or when the current
685 * task changes its own priority through {@link #setPri}.
686 *
687 * No task switch occurs when calling Task_self.
688 *
689 * Task_self will return NULL until Tasking is initiated at the end of
690 * BIOS_start().
691 *
692 * @b(returns) address of currently executing task object
693 */
694 Handle self();
695
696 /*!
697 * @_nodoc
698 * ======== checkStacks ========
699 * Check for stack overflow.
700 *
701 * This function is usually called by the {@link #HookSet} switchFxn to
702 * make sure task stacks are valid before performing the context
703 * switch.
704 *
705 * If a stack overflow is detected on either the oldTask or the
706 * newTask, a {@link #E_stackOverflow} Error is raised and the system
707 * exited.
708 *
709 * In order to work properly, {@link #checkStacks} requires that the
710 * {@link #initStackFlag} set to true, which it is by default.
711 *
712 * You can call {@link #checkStacks} directly from your application.
713 * For example, you can check the current task's stack integrity
714 * at any time with a call like the following:
715 *
716 * @p(code)
717 * Task_checkStacks(Task_self(), Task_self());
718 * @p
719 *
720 * @param(oldTask) leaving Task Object Ptr
721 * @param(newTask) entering Task Object Ptr
722 */
723 Void checkStacks(Handle oldTask, Handle newTask);
724
725 /*!
726 * ======== exit ========
727 * Terminate execution of the current task.
728 *
729 * Task_exit terminates execution of the current task, changing its mode
730 * from {@link #Mode_RUNNING} to {@link #Mode_TERMINATED}. If all tasks
731 * have been terminated, or if all remaining tasks have their
732 * vitalTaskFlag attribute set to FALSE, then DSP/BIOS terminates the
733 * program as a whole by calling the function System_exit with a status
734 * code of 0.
735 *
736 * Task_exit is automatically called whenever a task returns from its
737 * toplevel function.
738 *
739 * Exit Hooks (see exitFxn in {@link #HookSet}) can be used to provide
740 * functions that run whenever a task is terminated. The exitFxn Hooks
741 * are called before the task has been blocked and marked
742 * {@link #Mode_TERMINATED}.
743 *
744 * Any DSP/BIOS function can be called from an Exit Hook function.
745 *
746 * Calling {@link #self} within an Exit function returns the task
747 * being exited. Your Exit function declaration should be similar to
748 * the following:
749 * @p(code)
750 * Void myExitFxn(Void);
751 * @p
752 *
753 * A task switch occurs when calling Task_exit unless the program as a
754 * whole is terminated
755 *
756 * @a(constraints)
757 * Task_exit cannot be called from a Swi or Hwi.
758 *
759 * Task_exit cannot be called from the program's main() function.
760 */
761 Void exit();
762
763 /*!
764 * ======== sleep ========
765 * Delay execution of the current task.
766 *
767 * Task_sleep changes the current task's mode from {@link #Mode_RUNNING}
768 * to {@link #Mode_BLOCKED}, and delays its execution for nticks
769 * increments of the system clock. The actual time delayed can be up to
770 * 1 system clock tick less than nticks due to granularity in system
771 * timekeeping.
772 *
773 * After the specified period of time has elapsed, the task reverts to
774 * the {@link #Mode_READY} mode and is scheduled for execution.
775 *
776 * A task switch always occurs when calling Task_sleep if nticks > 0.
777 *
778 * @param(nticks) number of system clock ticks to sleep
779 *
780 * @a(constraints)
781 * Task_sleep cannot be called from a Swi or Hwi, or within a
782 * {@link #disable} / {@link #restore} block.
783 *
784 * Task_sleep cannot be called from the program's main() function.
785 *
786 * Task_sleep should not be called from within an Idle function. Doing
787 * so prevents analysis tools from gathering run-time information.
788 *
789 * nticks cannot be {@link ti.sysbios.BIOS#WAIT_FOREVER BIOS_WAIT_FOREVER}.
790 */
791 Void sleep(UInt nticks);
792
793 /*!
794 * ======== yield ========
795 * Yield processor to equal priority task.
796 *
797 * Task_yield yields the processor to another task of equal priority.
798 *
799 * A task switch occurs when you call Task_yield if there is an equal
800 * priority task ready to run.
801 *
802 * Tasks of higher priority preempt the currently running task without
803 * the need for a call to Task_yield. If only lower-priority tasks are
804 * ready to run when you call Task_yield, the current task continues to
805 * run. Control does not pass to a lower-priority task.
806 *
807 * @a(constraints)
808 * When called within an Hwi, the code sequence calling Task_yield
809 * must be invoked by the Hwi dispatcher.
810 *
811 * Task_yield cannot be called from the program's main() function.
812 */
813 Void yield();
814
815 /*!
816 * ======== getIdleTask ========
817 * returns a handle to idle task object
818 */
819 Handle getIdleTask();
820
821 /*!
822 * ======== getNickName ========
823 *
824 */
825 metaonly String getNickName(Any tskView);
826
827 instance:
828
829 /*!
830 * ======== create ========
831 * Create a Task.
832 *
833 * Task_create creates a new task object. If successful, Task_create
834 * returns the handle of the new task object. If unsuccessful,
835 * Task_create returns NULL unless it aborts.
836 *
837 * The fxn parameter uses the {@link #FuncPtr} type to pass a pointer to
838 * the function the Task object should run. For example, if myFxn is a
839 * function in your program, you can create a Task object to call that
840 * function as follows:
841 * @p(code)
842 * task = Task_create((Task_FuncPtr)myFxn, NULL, NULL);
843 * @p
844 * You can specify application-wide Create functions in your config
845 * file that run whenever a task is created. This includes tasks that
846 * are created statically and those created dynamically using
847 * Task_create.
848 *
849 * For Task objects created statically, Create functions are called
850 * during the Task module initialization phase of the program startup
851 * process prior to main().
852 *
853 * For Task objects created dynamically, Create functions
854 * are called after the task handle has been initialized but before the
855 * task has been placed on its ready queue.
856 *
857 * Any DSP/BIOS function can be called from Create functions.
858 * DSP/BIOS passes the task handle of the task being created to each of
859 * the Create functions.
860 *
861 * All Create function declarations should be similar to this:
862 * @p(code)
863 * Void myCreateFxn(Task_Handle task);
864 * @p
865 *
866 * The newly created task is placed in {@link #Mode_READY} mode, and is
867 * scheduled to begin concurrent execution of the following function
868 * call:
869 * @p(code)
870 * (*fxn)(arg1, arg2);
871 * @p
872 * As a result of being made ready to run, the task runs any
873 * application-wide Ready functions that have been specified.
874 *
875 * Task_exit is automatically called if and when the task returns
876 * from fxn.
877 *
878 * If params is NULL, the new task is assigned a default
879 * set of configuration parameters as described below.
880 *
881 * @param(fxn) Task Function
882 *
883 * @a(constraints)
884 * The fxn parameter and the name attribute cannot be NULL.
885 *
886 * The priority attribute must be less than or equal to
887 * ({@link #numPriorities} - 1) and greater than or equal to one (1)
888 * (priority 0 is owned by the Idle task).
889 *
890 * The priority can be less than zero (0) for tasks that should not
891 * execute.
892 *
893 * The stackHeap attribute must identify a valid memory Heap.
894 */
895 create(FuncPtr fxn);
896
897
898
899 /*! Task function argument. Default is 0 */
900 config UArg arg0 = 0;
901
902 /*! Task function argument. Default is 0 */
903 config UArg arg1 = 0;
904
905 /*!
906 * Task priority (0 to numPriorities-1 or -1).
907 * Default is 1.
908 */
909 config Int priority = 1;
910
911 /*!
912 * Task stack pointer. Default = null.
913 * null indicates that the stack is to be allocated by create().
914 *
915 * Example: To statically initialize "tsk0"'s stack to a literal
916 * address, use the following syntax:
917 *
918 * @p(code)
919 * Program.global.tsk0.stack = $addr(literal);
920 * @p
921 *
922 */
923 config Ptr stack = null;
924
925 /*!
926 * Task stack size in MAUs.
927 * The default value of 0 means that the module config
928 * {@link #defaultStackSize} is used.
929 */
930 config SizeT stackSize = 0;
931
932 /*!
933 * Mem section used for statically created task stacks.
934 * Default is inherited from module config defaultStackSection
935 */
936 metaonly config String stackSection;
937
938 /*!
939 * Mem heap used for dynamically created task stack.
940 * The default value of NULL means that the module config
941 * {@link #defaultStackHeap} is used.
942 */
943 config IHeap.Handle stackHeap = null;
944
945 /*! Environment data struct. */
946 config Ptr env = null;
947
948 /*!
949 * Exit system immediately when the last task with this
950 * flag set to TRUE has terminated. Default is true.
951 */
952 config Bool vitalTaskFlag = true;
953
954
955
956 /*!
957 * @_nodoc
958 * ======== getArg0 ========
959 * Returns arg0 passed via params to create.
960 *
961 * @b(returns) task's arg0
962 */
963 UArg getArg0();
964
965 /*!
966 * @_nodoc
967 * ======== getArg1 ========
968 * Returns arg1 passed via params to create.
969 *
970 * @b(returns) task's arg1
971 */
972 UArg getArg1();
973
974 /*!
975 * ======== getEnv ========
976 * Get task environment pointer.
977 *
978 * Task_getEnv returns the environment pointer of the specified task. The
979 * environment pointer references an arbitrary application-defined data
980 * structure.
981 *
982 * If your program uses multiple hook sets, {@link #getHookContext}
983 * allows you to get environment pointers you have set for a particular
984 * hook set and Task object combination.
985 *
986 * @b(returns) task environment pointer
987 */
988 Ptr getEnv();
989
990 /*!
991 * ======== getHookContext ========
992 * Get hook set's context for a task.
993 *
994 * @param(id) hook set ID
995 * @b(returns) hook set context for task
996 */
997 Ptr getHookContext(Int id);
998
999 /*!
1000 * ======== getPri ========
1001 * Get task priority.
1002 *
1003 * Task_getPri returns the priority of the referenced task.
1004 *
1005 * @b(returns) task priority
1006 */
1007 Int getPri();
1008
1009 /*!
1010 * @_nodoc
1011 * ======== setArg0 ========
1012 * Set arg0 (used primarily for legacy support)
1013 */
1014 Void setArg0(UArg arg);
1015
1016 /*!
1017 * @_nodoc
1018 * ======== setArg1 ========
1019 * Set arg1 (used primarily for legacy support)
1020 */
1021 Void setArg1(UArg arg);
1022
1023 /*!
1024 * ======== setEnv ========
1025 * Set task environment.
1026 *
1027 * Task_setEnv sets the task environment pointer to env. The
1028 * environment pointer references an arbitrary application-defined
1029 * data structure.
1030 *
1031 * If your program uses multiple hook sets, {@link #setHookContext}
1032 * allows you to set environment pointers for any
1033 * hook set and Task object combination.
1034 *
1035 * @param(env) task environment pointer
1036 */
1037 Void setEnv(Ptr env);
1038
1039 /*!
1040 * ======== setHookContext ========
1041 * Set hook instance's context for a task.
1042 *
1043 * @param(id) hook set ID
1044 * @param(hookContext) value to write to context
1045 */
1046 Void setHookContext(Int id, Ptr hookContext);
1047
1048 /*!
1049 * ======== setPri ========
1050 * Set a task's priority
1051 *
1052 * Task_setpri sets the execution priority of task to newpri, and returns
1053 * that task's old priority value. Raising or lowering a task's priority
1054 * does not necessarily force preemption and re-scheduling of the caller:
1055 * tasks in the {@link #Mode_BLOCKED} mode remain suspended despite a
1056 * change in priority; and tasks in the {@link #Mode_READY} mode gain
1057 * control only if their new priority is greater than that of the
1058 * currently executing task.
1059 *
1060 * The maximum value of newpri is ({@link #numPriorities} - 1).
1061 * The minimum value of newpri is one (1) (The Idle task owns priority 0).
1062 * If newpri is less than 0, the task is barred from further execution
1063 * until its priority is raised at a later time by another task; if newpri
1064 * equals ({@link #numPriorities} - 1), execution of the task effectively
1065 * locks out all other program activity, except for the handling of
1066 * interrupts.
1067 *
1068 * The current task can change its own priority (and possibly preempt its
1069 * execution) by passing the output of {@link #self} as the value of the
1070 * task parameter.
1071 *
1072 * A context switch occurs when calling Task_setpri if a currently
1073 * running task priority is set lower than the priority of another
1074 * currently ready task, or if another ready task is made to have a
1075 * higher priority than the currently running task.
1076 *
1077 * Task_setpri can be used for mutual exclusion.
1078 *
1079 * If a task's new priority is different than its previous priority,
1080 * then it's relative placement in it's new ready task priority
1081 * queue can be different than the one it was removed from. This can
1082 * effect the relative order in which it becomes the running task.
1083 *
1084 * The effected task is placed at the head of its new priority queue
1085 * if it is the currently running task. Otherwise it is placed at
1086 * at the end of its new task priority queue.
1087 *
1088 * @param(newpri) task's new priority
1089 * @b(returns) task's old priority
1090 *
1091 * @a(constraints)
1092 * newpri must be less than or equal to ({@link #numPriorities} - 1).
1093 *
1094 * The task cannot be in the {@link #Mode_TERMINATED} mode.
1095 *
1096 * The new priority should not be zero (0). This priority level is
1097 * reserved for the Idle task.
1098 */
1099 UInt setPri(Int newpri);
1100
1101 /*!
1102 * ======== stat ========
1103 * Retrieve the status of a task.
1104 *
1105 * Task_stat retrieves attribute values and status information about a
1106 * task.
1107 *
1108 * Status information is returned through statbuf, which references a
1109 * structure of type {@link #Stat}.
1110 *
1111 * When a task is preempted by a software or hardware interrupt, the task
1112 * execution mode returned for that task by Task_stat is still
1113 * {@link #Mode_RUNNING} because the task runs when the preemption ends.
1114 *
1115 * The current task can inquire about itself by passing the output of
1116 * {@link #self} as the first argument to Task_stat. However, the task
1117 * stack pointer (sp) in the {@link #Stat} structure is the value from
1118 * the previous context switch.
1119 *
1120 * Task_stat has a non-deterministic execution time. As such, it is not
1121 * recommended to call this API from Swis or Hwis.
1122 *
1123 * @param(statbuf) pointer to task status structure
1124 *
1125 * @a(constraints)
1126 * statbuf cannot be NULL;
1127 */
1128 Void stat(Stat *statbuf);
1129
1130 /*!
1131 * ======== getMode ========
1132 * Retrieve the {@link #Mode} of a task.
1133 */
1134 Mode getMode();
1135
1136 /*!
1137 * @_nodoc
1138 * ======== block ========
1139 * Block a task.
1140 *
1141 * Remove a task from its ready list.
1142 * The effect of this API is manifest the next time the internal
1143 * Task scheduler is invoked.
1144 * This can be done directly by embedding the call within a
1145 * {@link #disable}/{@link #restore} block.
1146 * Otherwise, the effect will be manifest as a result of processing
1147 * the next dispatched interrupt, or by posting a Swi, or by falling
1148 * through the task function.
1149 *
1150 * @a(constraints)
1151 * If called from within a Hwi or a Swi, or main(), there is no need
1152 * to embed the call within a {@link #disable}/{@link #restore} block.
1153 */
1154 Void block();
1155
1156 /*!
1157 * @_nodoc
1158 * ======== unblock ========
1159 * Unblock a task.
1160 *
1161 * Place task in its ready list.
1162 * The effect of this API is manifest the next time the internal
1163 * Task scheduler is invoked.
1164 * This can be done directly by embedding the call within a
1165 * {@link #disable}/{@link #restore} block.
1166 * Otherwise, the effect will be manifest as a result of processing
1167 * the next dispatched interrupt, or by posting a Swi, or by falling
1168 * through the task function.
1169 *
1170 * @a(constraints)
1171 * If called from within a Hwi or a Swi, or main(), there is no need
1172 * to embed the call within a {@link #disable}/{@link #restore} block.
1173 */
1174 Void unblock();
1175
1176 /*!
1177 * @_nodoc
1178 * ======== blockI ========
1179 * Block a task.
1180 *
1181 * Remove a task from its ready list.
1182 * Must be called within Task_disable/Task_restore block
1183 * with interrupts disabled.
1184 * This API is meant to be used internally.
1185 */
1186 Void blockI();
1187
1188 /*!
1189 * @_nodoc
1190 * ======== unblockI ========
1191 * Unblock a task.
1192 *
1193 * Place task in its ready list.
1194 * Must be called within Task_disable/Task_restore block
1195 * with interrupts disabled.
1196 * This API is meant to be used internally.
1197 *
1198 * @param(hwiKey) key returned from Hwi_disable()
1199 */
1200 Void unblockI(UInt hwiKey);
1201
1202
1203 internal:
1204
1205 /*! Target specific support functions. */
1206 proxy SupportProxy inherits ti.sysbios.interfaces.ITaskSupport;
1207
1208 1209 1210 1211 1212 1213
1214 Void schedule();
1215
1216 1217 1218 1219
1220 Void enter();
1221
1222 1223 1224 1225
1226 Void sleepTimeout(UArg arg);
1227
1228 1229 1230 1231
1232 Int postInit(Object *swi, Error.Block *eb);
1233
1234 1235 1236 1237 1238
1239 config UInt numConstructedTasks = 0;
1240
1241
1242 struct PendElem {
1243 Queue.Elem qElem;
1244 Task.Handle task;
1245 Clock.Handle clock;
1246 };
1247
1248 struct Instance_State {
1249 Queue.Elem qElem;
1250 volatile Int priority;
1251 UInt mask;
1252 Ptr context;
1253
1254 Mode mode;
1255 Ptr pendElem;
1256 SizeT stackSize;
1257 Char stack[];
1258 IHeap.Handle stackHeap;
1259 FuncPtr fxn;
1260 UArg arg0;
1261 UArg arg1;
1262 Ptr env;
1263 Ptr hookEnv[];
1264 Bool vitalTaskFlag;
1265
1266 Queue.Handle readyQ;
1267 };
1268
1269 struct Module_State {
1270 Bool locked;
1271 UInt curSet;
1272 Bool workFlag;
1273
1274
1275 UInt vitalTasks;
1276
1277 Handle curTask;
1278 Queue.Handle curQ;
1279 Queue.Object readyQ[];
1280 Queue.Object inactiveQ;
1281 Handle idleTask;
1282 Handle constructedTasks[];
1283
1284 };
1285 }
1286
1287 1288 1289
1290