The program creates four tasks:
Example 16-2 Sample Ada Tasking Program
1 -- Tasking program that demonstrates various tasking conditions. 2 3 package TASK_EXAMPLE_PKG is 4 procedure BREAK; 5 end; 6 7 package body TASK_EXAMPLE_PKG is 8 procedure BREAK is 9 begin 10 null; 11 end; 12 end; 13 14 15 with TEXT_IO; use TEXT_IO; 16 with TASK_EXAMPLE_PKG; use TASK_EXAMPLE_PKG; 17 procedure TASK_EXAMPLE is (1) 18 19 pragma TIME_SLICE(0.0); -- Disable time slicing. (2) 20 21 task type FATHER_TYPE is 22 entry START; 23 entry RENDEZVOUS; 24 entry BOGUS; -- Never accepted, caller deadlocks. 25 end FATHER_TYPE; 26 27 FATHER : FATHER_TYPE; (3) 28 29 task body FATHER_TYPE is 30 SOME_ERROR : exception; 31 32 task CHILD is (4) 33 entry E; 34 end CHILD; 35 36 task body CHILD is 37 begin 38 FATHER_TYPE.BOGUS; -- Deadlocks on call to its parent 39 end CHILD; -- (parent does not have an accept 40 -- statement for entry BOGUS). Whenever 41 -- a task-type name (here, FATHER_TYPE) 42 -- is used within a task body, the 43 -- name designates the task currently 44 -- executing the body. 45 begin -- (of FATHER_TYPE body) 46 47 accept START do 48 BREAK; -- Main program is waiting for this rendezvous to 49 -- complete; CHILD is suspended when it calls the 50 -- entry BOGUS. 51 null; 52 end START; 53 54 PUT_LINE("FATHER is now active and"); (5) 55 PUT_LINE("is going to rendezvous with main program."); 56 57 for I in 1..2 loop 58 select 59 accept RENDEZVOUS do 60 PUT_LINE("FATHER now in rendezvous with main program"); 61 end RENDEZVOUS; 62 or 63 terminate; 64 end select; 65 66 if I = 2 then 67 raise SOME_ERROR; 68 end if; 69 end loop; 70 71 exception 72 when OTHERS => 73 BREAK; -- CHILD is suspended on entry call to BOGUS. 74 -- Main program is going to delay while FATHER 75 -- terminates. 76 -- MOTHER is ready to begin executing. 77 abort CHILD; 78 BREAK; -- CHILD is now abnormal due to the abort statement. 79 80 raise; -- SOME_ERROR exception terminates FATHER. 81 end FATHER_TYPE; 82 83 begin -- (of TASK_EXAMPLE) (6) 84 85 declare 86 task MOTHER is (7) 87 entry START; 88 pragma PRIORITY (6); 89 end MOTHER; 90 91 task body MOTHER is 92 begin 93 accept START; 94 BREAK; -- At this point, the main program is waiting for 95 -- its dependents (FATHER and MOTHER) to terminate. 96 -- FATHER is terminated. 97 null; 98 end MOTHER; 99 begin (8) 100 101 102 BREAK; -- FATHER is suspended at accept start. 103 -- CHILD is suspended in its deadlock. 104 -- MOTHER has activated and ready to begin executing. 105 FATHER.START; (9) 106 BREAK; -- FATHER is suspended at its 'select or terminate' 107 -- statement. 108 109 110 FATHER.RENDEZVOUS; 111 FATHER.RENDEZVOUS; (10) 112 loop (11) 113 -- This loop causes the main program to busy wait 114 -- for the termination of FATHER, so that FATHER 115 -- can be observed in its terminated state. 116 if FATHER'TERMINATED then 117 exit; 118 end if; 119 delay 1.0; 120 end loop; 121 122 BREAK; -- FATHER has terminated by now with the unhandled 123 -- exception SOME_ERROR. CHILD no longer exists 124 -- because its master (FATHER) has terminated. Task 125 -- MOTHER is ready. 126 MOTHER.START; (12) 127 -- The main program enters a wait-for-dependents state, 128 -- so that MOTHER can finish executing. 129 end; 130 end TASK_EXAMPLE; (13)
Key to Example 16-2:
A task is an entity that executes in parallel with other tasks. A task is characterized by a unique task ID (see Section 16.3.3), a separate stack, and a separate register set.
The current definition of the active task and the visible task determine the context for manipulating tasks. See Section 16.3.1.
When specifying tasks in debugger commands, you can use any of the following forms:
The active task is the task that runs when a STEP, GO, CALL, or EXIT command executes. Initially, it is the task in which execution is suspended when the program is brought under debugger control. To change the active task during a debugging session, use the SET TASK/ACTIVE command.
Note
The SET TASK/ACTIVE command does not work for DECthreads (on both OpenVMS Alpha and VAX systems) or for Ada on OpenVMS Alpha systems, the tasking for which is implemented via DECthreads. Instead of SET TASK/ACTIVE, use the SET TASK/VISIBLE command on DECthreads for query-type actions. Or, to gain control to step through a particular thread, use a strategic placement of breakpoints.
The following command makes the task named CHILD the active task:
DBG> SET TASK/ACTIVE CHILD
The visible task is the task whose stack and register set are the current context that the debugger uses when looking up symbols, register values, routine calls, breakpoints, and so on. For example, the following command displays the value of the variable KEEP_COUNT in the context of the visible task:
DBG> EXAMINE KEEP_COUNT
Initially, the visible task is the active task. To change the visible task, use the SET TASK/VISIBLE command. This enables you to look at the state of other tasks without affecting the active task.
You can specify the active and visible tasks in debugger commands by using the built-in symbols %ACTIVE_TASK and %VISIBLE_TASK, respectively (see Section 16.3.4).
See Section 16.5 for more information about using the SET TASK command to modify task characteristics.
You declare a task either by declaring a single task or by declaring an object of a task type. For example:
-- TASK TYPE declaration. -- task type FATHER_TYPE is ... end FATHER_TYPE; task body FATHER_TYPE is ... end FATHER_TYPE; -- A single task. -- task MOTHER is ... end MOTHER; task body MOTHER is ... end MOTHER;
A task object is a data item that contains a task value. A task object is created when the program elaborates a single task or task object, when you declare a record or array containing a task component, or when a task allocator is evaluated. For example:
-- Task object declaration. -- FATHER : FATHER_TYPE; -- Task object (T) as a component of a record. -- type SOME_RECORD_TYPE is record A, B: INTEGER; T : FATHER_TYPE; end record; HAS_TASK : SOME_RECORD_TYPE; -- Task object (POINTER1) via allocator. -- type A is access FATHER_TYPE; POINTER1 : A := new FATHER_TYPE;
A task object is comparable to any other object. You refer to a task object in debugger commands either by name or by path name. For example:
DBG> EXAMINE FATHER DBG> EXAMINE FATHER_TYPE$TASK_BODY.CHILD
When a task object is elaborated, a task is created by the DEC Ada run-time library, and the task object is assigned its task value. As with other Ada objects, the value of a task object is undefined before the object is initialized, and the results of using an uninitialized value are unpredictable.
The task body of a task type or single task is implemented in DEC Ada as a procedure. This procedure is called by the DEC Ada run-time library when a task of that type is activated. A task body is treated by the debugger as a normal Ada procedure, except that it has a specially constructed name.
To specify the task body in a debugger command, use the following syntax to refer to tasks declared as task types:
task-type-identifier$TASK_BODY
Use the following syntax to refer to single tasks:
task-identifier$TASK_BODY
For example:
DBG> SET BREAK FATHER_TYPE$TASK_BODY
The debugger does not support the task-specific Ada attributes T'CALLABLE, E'COUNT, T'STORAGE_SIZE, and T'TERMINATED, where T is a task type and E is a task entry (see the DEC Ada documentation for more information on these attributes). You cannot enter commands such as EVALUATE CHILD'CALLABLE. However, you can get the information provided by each of these attributes with the debugger SHOW TASK command. For more information, see Section 16.4.
A task ID is the number assigned to a task when it is created by the tasking system. The task ID uniquely identifies a task during the entire execution of a program.
A task ID has the following syntax, where n is a positive decimal integer:
%TASK n
You can determine the task ID of a task object by evaluating or examining the task object. For example (Ada path-name syntax):
DBG> EVALUATE FATHER %TASK 2 DBG> EXAMINE FATHER TASK_EXAMPLE.FATHER: %TASK 2
If the programming language does not have built-in tasking services, you must use the EXAMINE/TASK command to obtain the task ID of a task.
Note that the EXAMINE/TASK/HEXADECIMAL command, when applied to a task object, yields the hexadecimal task value. The task value is the address of the task (or thread) control block of that task. For example (Ada example):
DBG> EXAMINE/HEXADECIMAL FATHER TASK_EXAMPLE.FATHER: 0015AD00 DBG>
The SHOW TASK/ALL command enables you to identify the task IDs that have been assigned to all currently existing tasks. Some of these existing tasks may not be immediately familiar to you for the following reasons:
The following examples are derived from Example 16-1 and Example 16-2, respectively:
DBG> SHOW TASK/ALL task id state hold pri substate thread_object %TASK 1 READY HOLD 12 Initial thread %TASK 2 SUSP 12 Condition Wait THREAD_EX1\main\threads[0].field1 %TASK 3 SUSP 12 Condition Wait THREAD_EX1\main\threads[1].field1 DBG>
DBG> SHOW TASK/ALL task id pri hold state substate task object * %TASK 1 7 RUN SHARE$ADARTL+130428 %TASK 2 7 SUSP Accept TASK_EXAMPLE.MOTHER+4 %TASK 4 7 SUSP Entry call TASK_EXAMPLE.FATHER_TYPE$TASK_BODY.CHILD+4 %TASK 3 6 READY TASK_EXAMPLE.MOTHER+4 DBG>
You can use task IDs to refer to nonexistent tasks in debugger conditional statements. For example, if you ran your program once, and you discovered that %TASK 2 and 3 were of interest, you could enter the following commands at the beginning of your next debugging session before %TASK 2 or 3 was created:
DBG> SET BREAK %LINE 60 WHEN (%ACTIVE_TASK=%TASK 2) DBG> IF (%CALLER=%TASK 3) THEN (SHOW TASK/FULL)
You can use a task ID in certain debugger commands before the task has been created without the debugger reporting an error (as it would if you used a task object name before the task object came into existence). A task does not exist until the task is created. Later the task becomes nonexistent sometime after it terminates. A nonexistent task never appears in a debugger SHOW TASK display.
Each time a program runs, the same task IDs are assigned to the same tasks so long as the program statements are executed in the same order. Different execution orders can result from ASTs (caused by delay statement expiration or I/O completion) being delivered in a different order. Different execution orders can also result from time slicing being enabled. A given task ID is never reassigned during the execution of the program.
The debugger built-in symbols defined in Table 16-2 enable you to specify tasks in command procedures and command constructs.
Examples using these task built-in symbols follow.
The following command displays the task ID of the visible task:
DBG> EVALUATE %VISIBLE_TASK
The following command places the active task on hold:
DBG> SET TASK/HOLD %ACTIVE_TASK
The following command sets a breakpoint on line 38 that triggers only when task CHILD executes that line:
DBG> SET BREAK %LINE 38 WHEN (%ACTIVE_TASK=CHILD)
The symbols %NEXT_TASK and %PREVIOUS_TASK enable you to cycle through the total set of tasks that currently exist. For example:
DBG> SHOW TASK %VISIBLE_TASK; SET TASK/VISIBLE %NEXT_TASK DBG> SHOW TASK %VISIBLE_TASK; SET TASK/VISIBLE %NEXT_TASK . . . DBG> EXAMINE MONITOR_TASK MOD\MONITOR_TASK: %TASK 2 DBG> WHILE %NEXT_TASK NEQ %ACTIVE DO (SET TASK %NEXT_TASK; SHOW CALLS)
The symbol %CALLER_TASK is specific to Ada tasks. It evaluates to the task ID of the task that called the entry associated with the accept statement. Otherwise, it evaluates to %TASK 0. For example, %CALLER_TASK evaluates to %TASK 0 if the active task is not currently executing the sequence of statements associated with the accept statement.
For example, suppose a breakpoint has been set on line 61 of Example 16-2 (within an accept statement). The accept statement in this case is executed by task FATHER (%TASK 2) in response to a call of entry RENDEZVOUS by the main program (%TASK 1). Thus, when an EVALUATE %CALLER_TASK command is entered at this point, the result is the task ID of the calling task, the main program:
DBG> EVALUATE %CALLER_TASK %TASK 1 DBG>
When the rendezvous is the result of an AST entry call, %CALLER_TASK evaluates to %TASK 0 because the caller is not a task.
To display information about one or more tasks of your program, use the SHOW TASK command.
The SHOW TASK command displays information about existing (nonterminated) tasks. By default, the command displays one line of information about the visible task.
Section 16.4.1 and Section 16.4.2 describe the information displayed by a SHOW TASK command for DECthreads and Ada tasks, respectively.
The command SHOW TASK displays information about all of the tasks of the program that currently exist (see Example 16-3).
Example 16-3 Sample SHOW TASK/ALL Display for DECthreads Tasks
(1) (2) (3) (4) (5) (6) task id state hold pri substate thread_object %TASK 1 SUSP 12 Condition Wait Initial thread %TASK 2 SUSP 12 Mutex Wait T_EXAMP\main\threads[0].field1 %TASK 3 SUSP 12 Delay T_EXAMP\main\threads[1].field1 %TASK 4 SUSP 12 Mutex Wait T_EXAMP\main\threads[2].field1 * %TASK 5 RUN 12 T_EXAMP\main\threads[3].field1 %TASK 6 READY 12 T_EXAMP\main\threads[4].field1 %TASK 7 SUSP 12 Mutex Wait T_EXAMP\main\threads[5].field1 %TASK 8 READY 12 T_EXAMP\main\threads[6].field1 %TASK 9 TERM 12 Term. by alert T_EXAMP\main\threads[7].field1 DBG>
Key to Example 16-3:
Task State | Description |
---|---|
RUNNING | Task is currently running on the processor. This is the active task. A task in this state can make a transition to the READY, SUSPENDED, or TERMINATED state. |
READY | Task is eligible to execute and waiting for the processor to be made available. A task in this state can make a transition only to the RUNNING state. |
SUSPENDED | Task is suspended, that is, waiting for an event rather than for the availability of the processor. For example, when a task is created, it remains in the suspended state until it is activated. A task in this state can make a transition only to the READY or TERMINATED state. |
TERMINATED | Task is terminated. A task in this state cannot make a transition to another state. |
Task Substate | Description |
---|---|
Condition Wait | Task is waiting on a DECthreads condition variable. |
Delay | Task is waiting at a call to a DECthreads delay. |
Mutex Wait | Task is waiting on a DECthreads mutex. |
Not yet started | Task has not yet executed its start routine. |
Term. by alert | Task has been terminated by an alert operation. |
Term. by exc | Task has been terminated by an exception. |
Timed Cond Wait | Task is waiting on a timed DECthreads condition variable. |
The SHOW TASK/FULL command provides detailed information about each task selected for display. Example 16-4 shows the output of this command for a sample DECthreads task.
Example 16-4 Sample SHOW TASK/FULL Display for a DECthreads Task
(1) task id state hold pri substate thread_object %TASK 4 SUSP 12 Delay T_EXAMP\main\threads[1].field1 (2) Alert is pending Alerts are deferred (3) Next pc: SHARE$CMA$RTL+46136 Start routine: T_EXAMP\thread_action (4) Scheduling policy: throughput (5) Stack storage: Bytes in use: 1288 (6) Base: 00334C00 Bytes available: 40185 SP: 003346F8 Reserved Bytes: 10752 Top: 00329A00 Guard Bytes: 4095 (7) Thread control block: Size: 293 Address: 00311B78 (8) Total storage: 56613 DBG>
4538P027.HTM OSSG Documentation 22-NOV-1996 13:02:12.26
Copyright © Digital Equipment Corporation 1996. All Rights Reserved.