[ 前のページ ]
[ 次のページ ]
[ 目次 ]
[ 索引 ]
[ DOC Home ]
本章では,タスキング・プログラム(マルチスレッド・プログラムとも呼ぶ) に固有のデバッガ機能について説明します。タスキング・プログラムは1 つのプロセス内に複数のタスクまたは実行スレッドを持っており,次のものを含んでいます。
デバッガで使用するタスクという用語は制御の流れのことであり, 言語や実現方法とは関係ありません。デバッガのタスキング・サポートは, 上記のようなプログラムすべてに適用されます。
本章では,DECthreads固有か言語固有の情報にはそのことを明記します。 第17.1節にDECthreads用語とAdaのタスキング用語の対応表を示します。
本章の機能を使用すれば,次のような処理を行うことができます。
これらの機能を使用するときには,同じタスキング・プログラムを実行してもそのときの状況によっては動作がデバッガにより変更されることがあるので注意してください。 たとえば,現在アクティブなタスクの実行をあるブレークポイントで中断しているとき, 入出力(I/O)の終了によるPOSIX 信号か非同期システム・トラップ(AST)が届いた場合は,ユーザの続行指示後ただちにその他のタスクが適格になることがあります。
DECthreadsやPOSIXスレッドについての詳しい説明は, 『Guide to DECthreads』を参照してください。Adaタスクについての詳しい説明はDEC Ada のマニュアルを参照してください。
マルチプロセス・プログラム(2つ以上のプロセスに分けて実行されるプログラム) のデバッグについては第15章を参照してください。
表 17-1にDECthreadsとAdaの用語とその意味の対応を示します。
DECthreads用語 | Ada用語 | 意味 |
---|---|---|
スレッド | タスク | 同じプロセス内の制御の流れ |
スレッド・オブジェクト | タスク・オブジェクト | 制御の流れを表すデータ項目 |
オブジェクト名または式 | タスク名または式 | 制御の流れを表すデータ項目 |
開始ルーチン | タスク本体 | 制御の流れに従って実行されるコード |
該当なし | 親タスク | 親タスクの制御の流れ |
該当なし | 依存タスク | なんらかの親タスクに制御される子タスクの制御の流れ |
同期化オブジェクト(ミューテクス, 条件変数) | ランデブ構造(エントリ呼び出しやaccept 文など) | 制御の流れを同期化する方法 |
スケジューリング方針およびスケジューリング優先順位 | タスク優先順位 | 実行のスケジューリング方法 |
警告処理 | abort 文 | 制御の流れの取り消し方法 |
スレッド状態 | タスク状態 | 実行の状態( 待ち,レディ,実行中,終了) |
スレッド作成属性( 優先順位,スケジューリング方針など) | プラグマ | パラレル・エンティティの属性 |
次の各項では,タスキング・プログラムのデバッグ時によく起こるエラーを含んでいるタスキング・ プログラムの例を示します。
本章のその他の例は,これらのプログラムを引用したものです。
例 17-1はマルチスレッドのCのプログラムです。 条件変数の使用法が間違っているのでブロッキングを起こします。
例のあとに説明が続いています。その説明のあとに,デバッガを使用してスレッドの相対的な実行を制御することによってブロッキングを診断する方法を示しています。
例 17-1では,初期スレッドにより, 計算作業を行う2 つのワーカ・スレッドが作成されます。これらのワーカ・ スレッドの作成後にSHOW TASK/ALLコマンドを実行すれば,それぞれが1 つのスレッドに対応する4つのタスクが表示されます。第17.4節にSHOW TASK コマンドの使用法が説明されています。
例 17-1では,ワーカ・スレッドのパスの行3893 に同期化点(条件待ち)が設けられています。行3877から始まるコメントは, このような直接的な呼び出しは間違ったプログラミング方法であることを示したうえで, 正しいコーディング方法を示しています。
このプログラムを実行すると,ワーカ・スレッドが大量の計算を行っているときに初期スレッドが条件変数をブロードキャストします。 条件変数をモニタしている最初のスレッドは初期スレッドのブロードキャストを検出してクリアし, 残りのスレッドを放置します。実行が妨げられ,プログラムは終了できなくなります。
3777 /* 定義 */ 3778 #define NUM_WORKERS 2 /* ワーカ・スレッドの数 */ 3779 3780 /* マクロ */ 3781 #define check(status,string) \ 3782 if (status == -1) perror (string); \ 3783 3784 /* グローバル変数 */ 3785 int cv_pred1; /* 条件変数の述語 */ 3786 pthread_mutex_t cv_mutex; /* 条件変数のミューテクス */ 3787 pthread_cond_t cv; /* 条件変数 */ 3788 pthread_mutex_t print_mutex; /* プリント・ミューテクス */ 3789 3790 /* ルーチン */ 3791 static pthread_startroutine_t 3792 worker_routine (pthread_addr_t arg); 3793 3794 main () 3795 { 3796 pthread_t threads[NUM_WORKERS]; /* ワーカ・スレッド */ 3797 int status; /* 戻り状態値 */ 3798 int exit; /* Join終了状態値 */ 3799 int result; /* Join結果値 */ 3800 int i; /* ループ索引 */ 3801 3802 /* ミューテクスの初期化 */ 3803 status = pthread_mutex_init (&cv_mutex, pthread_mutexattr_default); 3804 check (status, "cv_mutex initilization bad status"); 3805 status = pthread_mutex_init (&print_mutex, pthread_mutexattr_default); 3806 check (status, "print_mutex intialization bad status"); 3807 3808 /* 条件変数の初期化 */ 3809 status = pthread_cond_init (&cv, pthread_condattr_default); 3810 check (status, "cv condition init bad status"); 3811 3812 /* 条件変数の述語の初期化 */ 3813 cv_pred1 = 1; 【1】 3814 3815 /* ワーカ・スレッドの作成 */ 3816 for (i = 0; i < num_workers; i++) { 【2】 3817 status = pthread_create ( 3818 &threads[i], 3819 pthread_attr_default, 3820 worker_routine, 3821 0); 3822 check (status, "threads create bad status"); 3823 } 3824 3825 /* cv_pred1を偽に設定。可視性を保つためにロック内で行う。*/ 3826 3827 status = pthread_mutex_lock (&cv_mutex); 3828 check (status, "cv_mutex lock bad status"); 3829 3830 cv_pred1 = 0; 【3】 3831 3832 status = pthread_mutex_unlock (&cv_mutex); 3833 check (status, "cv_mutex unlock bad status"); 3834 3835 /* ブロードキャストの実施 */ 3836 status = pthread_cond_broadcast (&cv); 【4】 3837 check (status, "cv broadcast bad status"); 3838 3839 /* 両方のワーカ・スレッドの結合を試行 */ 3840 for (i = 0; i < num_workers; i++) { 【5】 3841 exit = pthread_join (threads[i], (pthread_addr_t*)&result); 3842 check (exit, "threads join bad status"); 3843 } 3844 } 3845 3846 static pthread_startroutine_t 3847 worker_routine(arg) 3848 pthread_addr_t arg; 【6】 3849 { 3850 int sum; 3851 int iterations; 3852 int count; 3853 int status; 3854 3855 /* 大量の計算を実施 */ 3856 for (iterations = 1; iterations < 10001; iterations++) { 3857 sum = 1; 3858 for (count = 1; count < 10001; count++) { 3859 sum = sum + count; 3860 } 3861 } 3862 3863 /* Printfはリエントラントとは限らないので,一度に1スレッドを実行 */ 3864 3865 status = pthread_mutex_lock (&print_mutex); 3866 check (status, "print_mutex lock bad status"); 3867 printf (" The sum is %d \n", sum); 3868 status = pthread_mutex_unlock (&print_mutex); 3869 check (status, "print_mutex unlock bad status"); 3870 3871 /* この条件変数のミューテクスをロックする。スレッドにより条件変数がブ*/ 3872 /* ロックされるとpthread_condによりそのミューテクスがアンロックされる*/ 3873 3874 status = pthread_mutex_lock (&cv_mutex); 3875 check (status, "cv_mutex lock bad status"); 3876 3877 /* 次の文では,条件待ち呼び出しのまわりをループし,その条件変数の述 */ 3878 /* 語をチェックするのが正しい条件待ちの構文ということになります。 */ 3879 /* そうすれば,ブロードキャスト済みの可能性がある条件変数を待った */ 3880 /* り,間違ったウェイクアップによって起動されるのを回避できます。そ */ 3881 /* のスレッド がウェイクアップされ,しかもその述語が偽であれば,実 */ 3882 /* 行が再開されます。正しい呼び出しは,たとえば次のようになります。 */ 3883 /* */ 3884 /* while (cv_pred1) { */ 3885 /* status = pthread_cond_wait (&cv, &cv_mutex); */ 3886 /* check (status, "cv condition wait bad status"); */ 3887 /* } */ 3888 /* */ 3889 /* 次のコーディングで使用されているような直接的な呼び出しでは, */ 3890 /* スレッドが間違ってウェイクアップされたり,この例のワーカ・ */ 3891 /* スレッドの1つと同様に永続的にブロックされることがあります。 */ 3892 3893 status = pthread_cond_wait (&cv, &cv_mutex); 【7】 3894 check (status, "cv condition wait bad status"); 3895 3896 /* 条件待ちでブロックされている間,そのルーチンはミューテクスを手放 */ 3897 /* しますが,制御が戻ったらミューテクスを取り出します。 */ 3898 3899 status = pthread_mutex_unlock (&cv_mutex); 3900 check (status, "cv_mutex unlock bad status"); 3901 3902 return (int)arg; 3903 }
次の番号は,例 17-1の番号に対応しています。
プログラマは,ブロードキャスト時にすべてのスレッドが条件変数を待っているようにするか, またはブロードキャストがすでに起こったことを対応する述語で明らかにすることによって, そのブロードキャストが確実に認識されるようにしなければならない。 このような方法は,この例では意図的に省いている。
デバッガを使用すればスレッドの相対的な実行を制御することにより,例 17-1 のような問題を診断することができます。 この例の場合は,初期スレッドの実行を中断してワーカ・スレッドに計算を終了させ, ワーカ・スレッドがブロードキャスト時に条件変数を待っているようにできます。 その手順は次のとおりです。
例 17-2はデバッグ中のタスキング・ プログラムによくあるエラーを示します。 この例のプロシージャBREAKの呼び出しは, ブレークポイントを設定したり各タスクの状態を観察する候補箇所です。 この例をデバッガ制御の下で実行する場合は,プロシージャBREAK の各呼び出しの箇所で次のコマンドを入力してブレークポイントを設定し, それぞれのブレークポイントで各タスクのそのときの状態を表示できます。
DBG> SET BREAK %LINE 46 DO (SHOW TASK/ALL) DBG> SET BREAK %LINE 71 DO (SHOW TASK/ALL) DBG> SET BREAK %LINE 76 DO (SHOW TASK/ALL) DBG> SET BREAK %LINE 92 DO (SHOW TASK/ALL) DBG> SET BREAK %LINE 100 DO (SHOW TASK/ALL) DBG> SET BREAK %LINE 104 DO (SHOW TASK/ALL) DBG> SET BREAK %LINE 120 DO (SHOW TASK/ALL)
このプログラムでは次の4つのタスクが作成されます。
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】
次の番号は,例 17-2の番号に対応しています。
VAXプロセッサでは,プラグマTIME_SLICEを省略するか値0.0 を指定すると,タイム・スライス機能は禁止される。
Alphaプロセッサでは,タイム・スライス機能を禁止するためにプラグマTIME_SLICE(0.0) を使用しなければならない。
起動されたタスクFATHERは,タスクCHILDが起動され,%TASK 3を指定されたタスクが作成されるのを待つ。CHILD は行38で1つのエントリ呼び出しを実行し, そのエントリが受け付けられないのでデッドロックになる(第17.7.1項を参照)。
タイム・スライス機能が禁止され,優先順位の高い実行可能なタスクがないので,FATHER は起動後も行47のACCEPT文でブロックされるまで実行される。
タスクとは,その他のタスクと並行して実行される要素です。 タスクには固有のタスクID(第17.3.3 項を参照),独立したスタック,および独立したレジスタ・セットが与えられます。
アクティブ・タスクと可視タスクの現在の定義により,タスク操作のコンテキストが決まります。 第17.3.1 項を参照してください。
デバッガ・コマンドにタスクを指定するときには,次のいずれかの形式で指定できます。
アクティブ・タスクとは,STEP,GO,CALL,またはEXITコマンドを実行したときに起動されるタスクです。 プログラムをデバッガの制御下に置くと, 最初はアクティブ・タスクの中で実行が中断されます。デバッグ・セッション中にアクティブ・ タスクを変更するにはSET TASK/ACTIVEコマンドを使用します。
次のコマンドではCHILDというタスクがアクティブ・タスクになります。
DBG> SET TASK/ACTIVE CHILD
可視タスクとは,スタックとレジスタ・セットがデバッガによって現在のコンテキストとして使用されるタスクです。 デバッガはシンボル, レジスタ値,ルーチン呼び出し,ブレークポイントなどを参照するときにスタックとレジスタ・ セットを使用します。たとえば,次のコマンドでは, 可視タスクのコンテキストの変数KEEP_COUNTの値が表示されます。
DBG> EXAMINE KEEP_COUNT
最初は,可視タスクがアクティブ・タスクです。可視タスクを変更するには,SET TASK/VISIBLE コマンドを使用します。このコマンドにより,アクティブ・ タスクに影響を与えずにその他のタスクの状態を参照することができます。
デバッガ・コマンドに組み込みシンボルの%ACTIVE_TASKと%VISIBLE_TASK を使用することにより,それぞれアクティブ・タスクと可視タスクを指定できます( 第17.3.4項を参照)。
SET TASKコマンドによるタスク特性の変更についての詳しい説明は,第17.5節を参照してください。
タスクを宣言するには,単一タスクを宣言するか,またはあるタスク型のオブジェクトを宣言します。 次に例を示します。
-- タスク型の宣言。 -- task type FATHER_TYPE is . . . end FATHER_TYPE; task body FATHER_TYPE is . . . end FATHER_TYPE; -- 単一タスク。 -- task MOTHER is . . . end MOTHER; task body MOTHER is . . . end MOTHER;
タスク・オブジェクトとは,タスク値を含むデータ項目です。 タスク・オブジェクトが作成されるのは,プログラムによって単一タスクかタスク・ オブジェクトが作成されるとき,タスク構成要素を含んでいる配列かレコードをユーザが宣言するとき, またはタスク・アロケータが評価されるときです。 次に例を示します。
-- タスク・オブジェクトの宣言。 -- FATHER : FATHER_TYPE; -- タスク・オブジェクト(T)はレコードの構成要素。 -- type SOME_RECORD_TYPE is record A, B: INTEGER; T : FATHER_TYPE; end record; HAS_TASK : SOME_RECORD_TYPE; -- タスク・オブジェクト(POINTER1)はアロケータを通じて作成される。 -- type A is access FATHER_TYPE; POINTER1 : A := new FATHER_TYPE;
タスク・オブジェクトは,その他のオブジェクトに似ています。デバッガ・ コマンドにタスク・オブジェクトを指定するときには,名前かパス名を指定します。 次に例を示します。
DBG> EXAMINE FATHER DBG> EXAMINE FATHER_TYPE$TASK_BODY.CHILD
タスク・オブジェクトを作成すると,DEC Ada実行時ライブラリによってタスクが作成され, そのタスク・オブジェクトにタスク値が割り当てられます。 タスク・オブジェクトの値はその他のAdaオブジェクトと同じく, オブジェクトが初期化されるまでは未定義になるので,初期化されていない値を使用するとその結果は予測できません。
あるタスク型または単一タスクのタスク本体は,1つのプロシージャとしてDEC Ada の中に組み込まれます。そのプロシージャはその型のタスクが起動されるとき,DEC Ada の実行時ライブラリから呼び出されます。 デバッガはタスク本体を普通のAdaプロシージャとして処理します。 特別な構造の名前を持っている点が異なります。
デバッガ・コマンドにタスク本体を指定するには,次の構文を使用して, タスク型として宣言されているタスクを指定します。
task-type-identifier$TASK_BODY
単一タスクの指定には,次の構文を使用します。
task-identifier$TASK_BODY
たとえば,次のように指定します。
DBG> SET BREAK FATHER_TYPE$TASK_BODY
デバッガはタスク依存のAda属性T'CALLABLE,E'COUNT,T'STORAGE_SIZE, およびT'TERMINATEDはサポートしません。このうち,Tはタスク型,E はタスク・エントリです(これらの属性についての詳しい説明は,DEC Adaの資料を参照してください)。EVALUATE CHILD'CALLABLEなどのコマンドは入力できません。 しかし,デバッガのSHOW TASKコマンドを使用してこれらの属性の内容を知ることはできます。 詳しい説明は,第17.4節を参照してください。
タスクIDとは,タスクがタスキング・システムによって作成されるときタスクに付けられる番号です。 タスクIDにより,タスクはプログラムの実行中は常に一意的に識別されます。
タスクIDの構文は次のとおりです。ただし,nは正の10進整数です。
%TASK n
あるタスク・オブジェクトのタスクIDを知るためには,そのタスク・オブジェクトを評価または検査します。 次はその一例です。パス名はAdaの構文に従っています。
DBG> EVALUATE FATHER %TASK 2 DBG> EXAMINE FATHER TASK_EXAMPLE.FATHER: %TASK 2
プログラミング言語に組み込みタスキング・サービスが用意されていない場合, タスクのタスクIDを得るためにはEXAMINE/TASKコマンドを使用しなければなりません。
EXAMINE/TASK/HEXADECIMALコマンドにタスク・オブジェクトを指定すると16 進のタスク値が表示されるので注意してください。タスク値とはそのタスクのタスク( すなわちスレッド)制御ブロックのアドレスです。次はその一例です(Ada の例)。
DBG> EXAMINE/HEXADECIMAL FATHER TASK_EXAMPLE.FATHER: 0015AD00 DBG>
SHOW TASK/ALLコマンドでは,現存するすべてのタスクに割り当てられているタスクID を表示することができます。これらのタスクの中には,次のような理由からユーザにとってはなじみのないものもあります。
次の各例は,それぞれ例 17-1と例 17-2 で実行したときのものです。
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>
タスクIDを使用すれば,デバッガの条件文に非存在タスクを指定できます。 たとえば,自分のプログラムを一度実行して,%TASK 2と%TASK 3を調べたい場合は, その次のデバッグ・セッションを開始して,まだ%TASK 2 も%TASK 3も作成されていないときに次のコマンドを入力します。
DBG> SET BREAK %LINE 60 WHEN (%ACTIVE_TASK=%TASK 2) DBG> IF (%CALLER=%TASK 3) THEN (SHOW TASK/FULL)
タスクが作成される前にそのタスクIDを特定のデバッガ・コマンドに指定しても, デバッガがエラーを報告することはありません。しかし,タスク・ オブジェクトが存在する前にそのタスク・オブジェクト名を使用すると, デバッガによりエラーが報告されます。タスクは作成されて初めて存在することになります。 タスクは終了後しばらくして非存在になります。 非存在タスクがデバッガのSHOW TASKコマンドによって表示されることはありません。
プログラムの文が同じ順序で実行されるかぎり,そのプログラムを実行するつど同じタスクには同じタスクID が割り当てられます。しかし, AST(delay文の満了や入出力(I/O)の完了で起こる)が異なる順序で発生するために実行順序が変わることがあります。 タイム・スライス機能を許可しても実行順序が変わることがあります。 同じプログラムの実行中に同じタスクID が2回以上割り当てられることはありません。
表 17-2に定義されているデバッガの組み込みシンボルを使用すれば, コマンド・プロシージャやコマンド構造にタスクを指定できます。
組み込みシンボル | 機能 |
---|---|
%ACTIVE_TASK | GO, STEP, CALL,またはEXIT コマンドの実行によって起動されるタスク。 |
%CALLER_TASK | Adaプログラムだけの機能。実行されるaccept 文のエントリを呼び出したタスク。 |
%NEXT_TASK | デバッガのタスク・リスト内の, 可視タスクの後のタスク。各タスクの順序はランダムだが,同じプログラムを1 回実行している間は首尾一貫している。 |
%PREVIOUS_TASK | デバッガのタスク・リスト内の, 可視タスクの前のタスク。 |
%VISIBLE_TASK | シンボル,レジスタ値,ルーチン呼び出し,ブレークポイントなどの参照に現在のコンテキストとして使用される呼び出しスタックとレジスタ・ セットを持っているタスク。 |
これらのタスク組み込みシンボルの使用例は次のとおりです。
次のコマンドでは,可視タスクのタスクIDが表示されます。
DBG> EVALUATE %VISIBLE_TASK
次のコマンドではアクティブ・タスクが保留されます。
DBG> SET TASK/HOLD %ACTIVE_TASK
次のコマンドでは行38にブレークポイントが設定されます。このブレークポイントはタスクCHILD が行38を実行するときにだけ検出されます。
DBG> SET BREAK %LINE 38 WHEN (%ACTIVE_TASK=CHILD)
シンボル%NEXT_TASKと%PREVIOUS_TASKを使用すれば,現存しているすべてのタスクを順次表示できます。 たとえば,次のように使用します。
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)
シンボル%CALLER_TASKはAdaのタスクだけに使用します。これが評価されると,accept 文のエントリを呼び出したタスクのタスクIDか,%TASK 0になります。 たとえば,アクティブ・タスクがaccept文に対応する一連の文を実行していないときに%CALLER_TASK が評価されると,%TASK 0になります。
たとえば,例 17-2の行61(accept文の中)にブレークポイントが設定されているものとします。 この例では,メイン・ プログラム(%TASK 1)がエントリRENDEZVOUSを呼び出すのに応じて,タスクFATHER(%TASK 2) がaccept文を実行します。したがって,そのときにEVALUATE %CALLER_TASK コマンドを入力すれば,呼び出しタスク,つまりメイン・ プログラムのタスクIDと評価されます。
DBG> EVALUATE %CALLER_TASK %TASK 1 DBG>
ASTによるエントリ呼び出しの結果がランデブのときに%CALLER_TASKを評価すると,%TASK 0 になります。呼び出す側がタスクでないからです。
プログラム内のタスクの情報を表示するには,SHOW TASKコマンドを使用します。
SHOW TASKコマンドでは,存在している(終了していない)タスクの情報が表示されます。 省略時の設定では,可視タスクの情報が1行だけ表示されます。
第17.4.1項と第17.4.2項には, それぞれ,SHOW TASK コマンドによって表示されるDECthreadsタスクとAdaタスクの情報が説明されています。
SHOW TASKコマンドでは,プログラム内に現存しているすべてのタスクの情報が表示されます( 例 17-3を参照) 。
【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>
次の番号は,例 17-3の番号に対応しています。
タスクの状態 | 説明 |
---|---|
RUNNING | タスクは現在プロセッサで実行中である。 これがアクティブ・タスクである。この状態のタスクが移ることができるのは,READY, SUSPENDED, TERMINATED のいずれかの状態である。 |
READY | タスクは実行適格であり, プロセッサが使用可能になるのを待っている。この状態のタスクが移ることができるのはRUNNING 状態だけである。 |
SUSPENDED | タスクは中断している。 つまり,プロセッサが使用できるのを待っているのではなく,あるイベントを待っている。 たとえば,タスクは作成されてから起動されるまで中断状態に留まる。 この状態のタスクが移ることができるのは, READY状態またはTERMINATED状態だけである。 |
TERMINATED | タスクは終了している。この状態のタスクは, ほかの状態に移ることはできない。 |
タスクの副次状態 | 説明 |
---|---|
Condition Wait | タスクはDECthreadsの条件変数を待っている。 |
Delay | タスクはDECthreads遅延への呼び出しで待っている。 |
Mutex Wait | タスクはDECthreadsミューテクスを待っている。 |
Not yet started | タスクはまだその起動ルーチンを実行していない。 |
Term. by alert | タスクは警告処理により打ち切られた。 |
Term. by exc | タスクは例外により打ち切られた。 |
Timed Cond Wait | タスクは時限DECthreads条件変数を待っている。 |
SHOW TASK/FULLコマンドでは,選択した各タスクについての詳細情報が表示されます。 例 17-4に,DECthreadsタスクの例でこのコマンドを実行した場合の出力を示します。
【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>
次の番号は,例 17-4の番号に対応しています。
図 17-1にタスク・スタックを示します。
SHOW TASK/STATISTICSコマンドでは,プログラム内のすべてのタスクについての統計情報が報告されます。 例 17-5には,DECthreads タスクのプログラム例に対してSHOW TASK/STATISTICS/FULL コマンドを実行したときの出力が示されています。 この情報により,プログラムの性能を測定できます。 スケジューリング(コンテキスト・スイッチとも呼ぶ)の合計回数が多いほど, タスキング・オーバヘッドは大きくなります。
task statistics Total context switches: 0 Number of existing threads: 0 Total threads created: 0 DBG>
SHOW TASK/ALLコマンドでは,プログラム内に現存しているすべてのタスクの情報, つまりタスク自体が作成されてからその親がまだ終了していないすべてのタスクの情報が表示されます( 例 17-6を参照)。
【1】 【2】【3】 【4】 【5】 【6】 task id pri hold state substate task object * %TASK 1 7 RUN SHARE$ADARTL+130428 %TASK 2 7 HOLD 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) DBG>
次の番号は,例 17-6の番号に対応しています。
VAXプロセッサで作成されるタスクは省略時の設定である優先順位7 が割り当てられる。ただし,それ以外の優先順位がプラグマPRIORITY で指定されている場合は,その優先順位が割り当てられる。
Alphaプロセッサで作成されるタスクは, タイム・スライス機能が使用不能ならば,省略時の設定である優先順位7 が割り当てられる。タイム・スライス機能が使用可能ならば, プラグマPRIORITYが指定されていないかぎり,適当な中間の値が優先順位として割り当てられる。
タスクの副次状態 | 説明 |
---|---|
Abnormal | タスクは強制終了された。 |
Accept | タスクはselect 文の外のaccept文で待っている。 |
Activating | タスクはその宣言部分を作成中である。 |
Activating tasks | タスクは自分が作成した各タスクが活動を終了するのを待っている。 |
Completed [abn] | タスクはabort 文のために打ち切られたが,まだ終了していない。Ada でいう打ち切られたタスクとは,そのend文で各依存タスクを待っているタスクである。 それらの依存タスクが終了すると,タスクの状態はTerminated に変わる。 |
Completed [exc] | タスクは処理されない例外[1]のために打ち切られたが, まだ終了していない。Adaでいう打ち切られたタスクとは,そのend 文で各依存タスクを待っているタスクである。それらの依存タスクが終了すると, タスクの状態はTerminatedに変わる。 |
Completed | タスクは打ち切られている。abort 文は実行されず,処理されない例外[1]は起こっていない。 |
Delay | タスクはdelay 文で待っている。 |
Dependents | タスクは各依存タスクの終了を待っている。 |
Dependents [exc] | タスクは処理されない例外 [1]の通知を依存タスクが許すのを待っている。 |
Entry call | タスクはそのエントリ呼び出しが受け付けられるのを待っている。 |
Invalid state | DEC Adaの実行時ライブラリにエラーがある。 |
I/OまたはAST | タスクは入出力(I/O) の終了かなんらかのASTを待っている。 |
Not yet activated | タスクは,自分を作成したタスクによって起動されるのを待っている。 |
Select or delay | タスクは遅延という代替方法が可能なselect 文で待っている。 |
Select or terminate | タスクは終了という代替方法が可能なselect 文で待っている。 |
Select | タスクはno else,遅延,終了のいずれも不可能なselect文で待っている。 |
Shared resource | タスクは内部共用リソースを待っている。 |
Terminated [abn] | タスクはabort文により終了した。 |
Terminated [exc] | タスクは処理されない例外 [1]により終了した。 |
Terminated | タスクは正常終了した。 |
Timed entry call | タスクは時限エントリ呼び出しをして待っている。 |
[1]処理されない例外とは,現在のフレーム内にそのためのハンドラがない例外, またはハンドラがあってraise文を実行しその例外を外部有効範囲に通知する例外のことです。 |
図 17-1はタスク・スタックを示します。
SHOW TASK/FULLコマンドでは,選択した各タスクについての詳細情報が表示されます。 例 17-7には,Ada タスク例に対してこのコマンドを実行したときの出力が示されています。
【1】task id pri hold state substate task object * %TASK 2 7 RUN TASK_EXAMPLE.MOTHER+4 【2】 Waiting entry callers: Waiters for entry BOGUS: %TASK 4, type: CHILD 【3】 Task type: FATHER_TYPE Created at PC: TASK_EXAMPLE.%LINE 14+22 Parent task: %TASK 1 Start PC: TASK_EXAMPLE.FATHER_TYPE$TASK_BODY 【4】 Task control block: 【5】Stack storage (bytes): Task value: 490816 RESERVED_BYTES: 10640 Entries: 3 TOP_GUARD_SIZE: 5120 Size: 1488 STORAGE_SIZE: 30720 【6】 Stack addresses: Bytes in use: 456 Top address: 001EB600 Base address: 001F2DFC 【7】 Total storage: 47968 DBG>
次の番号は,例 17-7の番号に対応しています。
VAXシステムでは,保護領域ページとして割り当てるバイト数は,DEC AdaプラグマのTASK_STORAGEとMAIN_STORAGEに指定できる。デバッガにより表示される値は, 割り当てられたバイト数である。プラグマの値は, ページ数が整数になるように,必要に応じて切り上げられる。これらのプラグマと上部記憶保護領域についての詳しい説明は,DEC Ada のマニュアルを参照。
Alphaシステムでは,保護領域ページとして割り当てるバイト数は, DEC AdaプラグマのTASK_STORAGEに指定できる。デバッガにより表示される値は, 割り当てられたバイト数である。プラグマの値は,ページ数が整数になるように, 必要に応じて切り上げられる。これらのプラグマと上部記憶保護領域についての詳しい説明は,DEC Ada のマニュアルを参照。
VAXシステムでは,割り当てるバイト数は,T'STORAGE_SIZE表現句かAda プラグマのMAIN_STORAGEに指定する。デバッガにより表示される値は, 割り当てられたバイト数である。指定した値は,ページ数が整数になるように, 必要に応じて切上げられる。この表現句とプラグマおよびタスク起動用( 作業用)記憶域についての詳しい説明は,DEC Adaのマニュアルを参照。
AXPシステムでは,割り当てるバイト数は,T'STORAGE_SIZE表現句で指定する。 デバッガにより表示される値は,割り当てられたバイト数である。 指定した値は,ページ数が整数になるように,必要に応じて切上げられる。 この表現句とプラグマおよびタスク起動用(作業用)記憶域についての詳しい説明は,DEC Ada のマニュアルを参照。
SHOW TASK/STATISTICSコマンドでは,プログラム内のすべてのタスクについての統計情報が報告されます。 例 17-8は,VAX プロセッサでAdaタスキング・ プログラム例に対してSHOW TASK/STATISTICS/FULLコマンドを実行したときの出力です。 この情報により,プログラムの性能を測定できます。 スケジューリング(コンテキスト・スイッチとも呼ぶ)の総数が多いほど, タスキング・オーバヘッドは大きくなります。
task statistics Entry calls = 4 Accepts = 1 Selects = 2 Tasks activated = 3 Tasks terminated = 0 ASTs delivered = 4 Hibernations = 0 Total schedulings = 15 Due to readying a higher priority task = 1 Due to task activations = 3 Due to suspended entry calls = 4 Due to suspended accepts = 1 Due to suspended selects = 2 Due to waiting for a DELAY = 0 Due to scope exit awaiting dependents = 0 Due to exception awaiting dependents = 0 Due to waiting for I/O to complete = 0 Due to delivery of an AST = 4 Due to task terminations = 0 Due to shared resource lock contention = 0 DBG>
デバッグ中にタスクの特性やタスキング環境を変更するには,次表のSET TASKコマンドを使用します。
コマンド | 機能 |
---|---|
SET TASK/ACTIVE | 指定されたタスクをアクティブ・ タスクにする。DECthreads(OpenVMS AlphaシステムまたはVAX システム)でもAda(OpenVMS Alphaシステム)でも動作しない(第17.3.1項を参照)。 |
SET TASK/VISIBLE | 指定されたタスクを可視タスクにする( 第17.3.1項を参照) 。 |
SET TASK/ABORT | 次に可能な機会にタスクを終了するように要求する。 具体的な効果はそのときのイベント機能により異なる( 言語依存)。Adaタスクの場合, これはabort文の実行と同じである。 |
SET TASK/PRIORITY | タスクの優先順位を設定する。具体的な効果はそのときのイベント機能により異なる( 言語依存)。 |
SET TASK/RESTORE | タスクの優先順位を復元する。 具体的な効果はそのときのイベント機能により異なる(言語依存) 。 |
SET TASK/[NO]HOLD | タスク・スイッチを制御する。タスク状態の遷移については第17.5.1項を参照。 |
SET TASK/TIME_SLICE | タイム・スライス値を制御するか, タイム・スライス機能を禁止する。VAX Adaのみでサポートされ, DECthreadsではサポートされていない(第17.5.2 項を参照)。 |
詳細については,SET TASKコマンドの説明を参照してください。
タスク・スイッチにより,プログラムのデバッグが複雑になります。SET TASK/HOLDコマンドを使用してタスクを保留すれば,あとでそのプログラムが実行可能になったときにそのタスクが移る状態を制限できます。
保留されたタスクはRUNNING以外のいずれかの状態に移ります。しかし, 必要であればSET TASK/ACTIVEコマンドを使用して保留されたタスクをRUNNING 状態に移すことも可能です。
SET TASK/HOLD/ALLコマンドではアクティブ・タスク以外のすべてのタスクの状態が凍結されます。 このコマンドをSET TASK/ACTIVEコマンドと併用すれば, 指定した1つか複数のタスクの動作を観察できます。そのためには,STEP コマンドまたはGOコマンドによってそのアクティブ・タスクを実行し,SET TASK/ACTIVE コマンドを使用して実行を別のタスクに切り替えます。 次に例を示します。
DBG> SET TASK/HOLD/ALL DBG> SET TASK/ACTIVE %TASK 1 DBG> GO . . . DBG> SET TASK/ACTIVE %TASK 3 DBG> STEP . . .
タスクを保留する必要がなくなったら,SET TASK/NOHOLDコマンドを使用します。
タイム・スライス機能を使用するタスキング・プログラムのデバッグは複雑です。 タイム・スライス機能によってタスクの相対的な動作が非同期になるからです。 タイム・スライス機能を使用しない場合,タスクの実行はタスクの優先順位だけで決まります。 タスク・スイッチは予測可能なので, 実行のたびにプログラムの同じ動作を繰り返すことができます。タイム・ スライス機能を使用する場合もタスクの優先順位によってタスク・スイッチが行われますが, 指定期間は同じ優先順位の複数のタスクが交互に実行されます。 したがって,タイム・スライス機能があれば各タスクは互いにいっそう独立して実行されるようになります。 そのため,タイム・スライス機能を使用するプログラムは, 実行するたびに同じ動作を繰り返さないことがあります。
SET TASK/TIME_SLICE=tコマンド(VAX Adaのみでサポート) を使用すれば,新しいタイム・スライスを指定したり,SET TASK/TIME_ SLICE=0.0と指定してタイム・スライス機能を禁止したりできます。したがって, タスキング・プログラムの実行を調整したり,タスクの実行順序に依存する問題を診断したりできます。
%DEBUG-E-NOTIMSLI, time slice modification not supported by this event facility
タイム・スライス機能とデバッガのウォッチポイントの実行とは,互いに影響を与えることに注意してください。 ウォッチポイントを設定すると, タイム・スライス間隔値はデバッガにより自動的に10.0秒に増加されることがあります。 タイム・スライス速度を遅くすることにより,発生を防げる問題があるからです。
次の各項では,次の各機能の実行方法について説明します。
イベントポイントとは,デバッガに制御を戻すために使用できるイベントです。 ブレークポイント,トレースポイント,ウォッチポイント, およびSTEPコマンドの終了はいずれもイベントポイントです。
タスク非依存イベントポイントは,プログラム内のいずれかのタスクの実行によって起動されます。 そのイベントポイントの設定時にどのタスクがアクティブなのかは関係ありません。 タスク非依存イベントポイントの指定には, 行番号や名前などのアドレス式を使用するのが普通です。 ウォッチポイントはすべて,タスク非依存イベントポイントです。 次にタスク非依存イベントポイントの設定例を示します。
DBG> SET BREAK COUNTER DBG> SET BREAK/NOSOURCE %LINE 55, CHILD$TASK_BODY DBG> SET WATCH/AFTER=3 KEEP_COUNT
タスク依存イベントポイントは,コマンド入力時にアクティブなタスクにしか設定できません。 タスク依存イベントポイントは, その同じタスクがアクティブなときにしか起動されません。たとえば, STEP/LINEコマンドはタスク依存イベントポイントです。その他のタスクが同じソース行を実行してもそのイベントは起動されないことがあります。
次の修飾子を指定してSET BREAK, SET TRACE,またはSTEPコマンドを実行すれば, タスク依存イベントポイントが設定されます。
これらのコマンドでこれらの修飾子を使用しないで設定するイベントポイントおよびSET WATCH コマンドを使用して設定するイベントポイントは, タスク非依存になります。次にタスク依存イベントポイントの設定例を示します。
DBG> SET BREAK/INSTRUCTION DBG> SET TRACE/INSTRUCTION/SILENT DO (EXAMINE KEEP_COUNT) DBG> STEP/CALL/NOSOURCE
通常はタスク非依存のイベントポイントに条件を設定して,タスク依存にすることができます。 次に例を示します。
DBG> SET BREAK %LINE 11 WHEN (%ACTIVE_TASK=FATHER)
ブレークポイントをスレッド起動ルーチンに設定することは可能です。そのようなブレークポイントは, 起動ルーチンの実行開始直前に検出されます。 例 17-1の場合は,この型のブレークポイントはたとえば次のように設定します。
DBG> SET BREAK worker_routine
Adaタスクの場合とは異なりDECthreadsタスクの場合は名前で本体を指定することはできませんが, 起動ルーチンは似ています。
SET BREAKコマンドにWHEN句を指定すれば,特定のスレッドの実行開始時点を確実にとらえることができます。 次に例を示します。
DBG> SET BREAK worker_routine - _DBG> WHEN (%CALLER_TASK = %TASK 4)
例 17-1の場合,この条件付きブレークポイントは2 番目のワーカ・スレッドがその起動ルーチンを開始するときに検出されます。
ブレークポイントの設定に適するその他の箇所には,条件待ち,結合,およびミューテクスのロックの直前と直後があります。 そのようなブレークポイントの設定には, 行番号かルーチン名を指定します。
タスク本体にブレークポイントを設定するには,次のどちらかの構文に従ってタスク本体を指定します( 第17.3.2 項を参照)。
task-type-identifier$TASK_BODY
task-identifier$TASK_BODY
たとえば,次のコマンドではタスクCHILDの本体にブレークポイントが設定されます。 そのブレークポイントは,タスクの宣言部分の作成(タスクのアクティベーションとも呼ぶ) の直前に検出されます。
DBG> SET BREAK CHILD$TASK_BODY
CHILD$TASK_BODYは,タスクが最初に実行する命令が置かれている箇所の名前です。 ブレークポイントをある命令に設定するのは意味があることなので, この名前を指定します。しかし,SET BREAKコマンドにタスク・オブジェクトの名前( たとえば,CHILD)を指定してはなりません。タスク・ オブジェクト名は,データ項目のアドレス(32ビットのタスク値)を示します。 整数オブジェクトにブレークポイントを設定するのは間違いであるように, タスク・オブジェクト名にブレークポイントを設定するのも間違いです。
エントリ呼び出し文とaccept文にブレークポイントかトレースポイントを設定すれば, 呼ぶ側,呼ばれる側のタスクの実行をモニタできます。
ブレークポイントやトレースポイントの設定に適する箇所は,accept文とその前後に数箇所あります。 たとえば,RENDEZVOUSという同じエントリに2 つのaccept文が使用されている次のプログラム・セグメントについて考えてみます。
8 task body TWO_ACCEPTS is 9 begin 10 for I in 1..2 loop 11 select 12 accept RENDEZVOUS do 13 PUT_LINE("This is the first accept statement"); 14 end RENDEZVOUS; 15 or 16 terminate; 17 end select; 18 end loop; 19 accept RENDEZVOUS do 20 PUT_LINE("This is the second accept statement"); 21 end RENDEZVOUS; 22 end TWO_ACCEPTS;
この例では,次の箇所にブレークポイントかトレースポイントを設定できます。
accept文かその前後にブレークポイントかトレースポイントを設定するためには, その行番号を指定します。たとえば,次のコマンドでは,前の例の最初のacce pt 文の先頭と本体にブレークポイントが設定されます。
DBG> SET BREAK %LINE 12, %LINE 13
accept文の本体にブレークポイントかトレースポイントを設定するには, エントリ名も使用できます。その展開された名前を指定して,そのエントリが宣言されているタスク本体を示します。 次に例を示します。
DBG> SET BREAK TWO_ACCEPTS$TASK_BODY.RENDEZVOUS
同じエントリに2つ以上のaccept文がある場合,デバッガはそのエントリをオーバロードされた名前として扱います。 デバッガからそのシンボルがオーバロードされていることを示すメッセージが発行されるので, ユーザはSHOW SYMBOL コマンドを使用して,デバッガによって割り当てられたオーバロードされた名前を表示しなければなりません。 次に例を示します。
DBG> SHOW SYMBOL RENDEZVOUS overloaded symbol TEST.TWO_ACCEPTS$TASK_BODY.RENDEZVOUS overloaded instance TEST.TWO_ACCEPTS$TASK_BODY.RENDEZVOUS__1 overloaded instance TEST.TWO_ACCEPTS$TASK_BODY.RENDEZVOUS__2
オーバロードされた名前の後ろには,2つの下線と整数が続きます。オーバロードされた名前についての詳しい説明は, デバッガのオンライン・ヘルプを参照してください(Help Language_Support Ada を入力します)。
オーバロードされた名前のどちらが特定のaccept文に対応しているかを知るためには,EXAMINE/SOURCE コマンドを使用します。次に例を示します。
DBG> EXAMINE/SOURCE TWO_ACCEPTS$TASK_BODY.RENDEZVOUS__1 module TEST_ACCEPTS 12: accept RENDEZVOUS do DBG> EXAMINE/SOURCE TWO_ACCEPTS$TASK_BODY.RENDEZVOUS__2 module TEST_ACCEPTS 19: accept RENDEZVOUS do
次の例でブレークポイントが検出されると,呼び出しタスクが評価されます。 シンボル%CALLER_TASKについての詳しい説明は,第17.3.4項を参照してください。
DBG> SET BREAK TWO_ACCEPTS$TASK_BODY.RENDEZVOUS__2 - _DBG> DO (EVALUATE %CALLER_TASK)
次のブレークポイントが検出されるのは,呼び出しタスクが%TASK 2のときだけです。
DBG> SET BREAK TWO_ACCEPTS$TASK_BODY.RENDEZVOUS__2 - _DBG> WHEN (%CALLER_TASK = %TASK 2)
呼び出しタスクが同じaccept文に2回以上エントリ呼び出しを行う場合は,SHOW TASK/CALLS コマンドを使用することにより,そのエントリ呼び出しが実行されたソース行を表示できます。 たとえば,次のように指定します。
DBG> SET BREAK TWO_ACCEPTS$TASK_BODY.RENDEZVOUS__2 - _DBG> DO (SHOW TASK/CALLS %CALLER_TASK)
SET BREAK/EVENTコマンドとSET TRACE/EVENTコマンドを使用すれば,タスク・ イベントと例外イベントによって検出されるブレークポイントおよびトレースポイントを設定できます。 たとえば,次のコマンドで設定するトレースポイントは, タスクCHILDか%TASK 2がRUN状態に移るときに検出されます。
DBG> SET TRACE/EVENT=RUN CHILD,%TASK 2
あるイベントの結果,ブレークポイントかトレースポイントが検出されると, デバッガはそのイベントを識別し,追加情報を与えます。
次の各表に,SET BREAK/EVENTコマンドとSET TRACE/EVENTコマンドに指定できるイベント名キーワードの一覧を示します。
イベント名 | 機能 |
---|---|
RUN | タスクが実行する直前に検出される。 |
PREEMPTED | RUN状態にあるタスクが強制的にREADY 状態に移される直前に検出される( 表 17-3 を参照)。 |
ACTIVATING | タスクが実行を開始する直前に検出される。 |
SUSPENDED | タスクが中断される直前に検出される。 |
イベント名 | 機能 |
---|---|
HANDLED | あるTRYブロックで例外が処理される直前に検出される。 |
TERMINATED | タスクが終了する直前に検出される(警告や例外による場合を含む) 。 |
EXCEPTION_TERMINATED | タスクが例外によって終了する直前に検出される。 |
FORCED_TERM | タスクが警告処理によって終了する直前に検出される。 |
イベント名 | 機能 |
---|---|
HANDLED | 例外がAdaの例外ハンドラ(その他のハンドラを含む) によって処理される直前に検出される。 |
HANDLED_OTHERS | 例外がその他のAda例外ハンドラによって処理される直前にだけ検出される。 |
RENDEZVOUS_EXCEPTION | 例外がランデブの外に通知される直前に検出される。 |
DEPENDENTS_ EXCEPTION | 例外によってタスクがある有効範囲内の依存タスクを待つ直前に検出される( 未処理例外[1]を含む。したがって, Adaの実行時ライブラリ内部の特殊な例外を含む。詳しくは,DEC Ada のマニュアルを参照)。デッドロックの直前のことが多い。 |
TERMINATED | タスクの終了直前に検出される。 正常終了のとき,abort文によるとき,および例外によるときを含む。 |
EXCEPTION_TERMINATED | 処理されない例外[1]によってタスクが終了する直前に検出される。 |
ABORT_TERMINATED | abort文によってタスクが終了する直前に検出される。 |
[1]未処理例外とは,現在のフレーム内にそのためのハンドラがない例外, またはハンドラがあってraise文を実行しその例外を外部有効範囲に通知する例外のことです。 |
上記の各表には,例外関係のイベントも含めてあります。次の各段落では, タスク・イベントについてだけ説明しています。例外イベントについての詳しい説明は, デバッガのオンライン・ヘルプを参照してください(type Help Language_Support Ada を入力します)。
イベント名キーワードは,一意性を損わない文字数まで短縮できます。
SET BREAK/EVENTコマンドまたはSET TRACE/EVENTコマンドに指定できるイベント名キーワードは, そのときのイベント機能がタスク・イベント時にTHREADS なのかADAなのかで異なります。プログラムをデバッガの制御下に置くと, 適切なイベント機能が自動的に設定されます。SHOW EVENT_ FACILITYコマンドでは,現在設定されている機能が示され,その機能に指定できるイベント名キーワード( 汎用イベントのキーワードを含む)の一覧が表示されます。
以後,いくつかの例によって/EVENT修飾子の使用法を示します。
DBG> SET BREAK/EVENT=PREEMPTED DBG> GO break on THREADS event PREEMPTED Task %TASK 4 is getting preempted by %TASK 3 . . . DBG> SET BREAK/EVENT=SUSPENDED DBG> GO break on THREADS event SUSPENDED Task %TASK 1 is about to be suspended . . . DBG> SET BREAK/EVENT=TERMINATED DBG> GO break on THREADS event TERMINATED Task %TASK 4 is terminating normally DBG>
プログラムをデバッガの制御下に置くと,次の定義済みイベント・ブレークポイントが自動的に設定されます。
以後,Adaでの定義済みおよびその他の型のイベント・ブレークポイント例を示します。
EXCEPTION_TERMINATEDイベントが起動されるときには,通常,予期しないプログラム・ エラーが示されます。次に例を示します。
. . . break on ADA event EXCEPTION_TERMINATED Task %TASK 2 is terminating because of an exception %ADA-F-EXCCOP, Exception was copied at a "raise;" or "accept" -ADA-F-EXCEPTION, Exception SOME_ERROR -ADA-F-EXCRAIPRI, Exception raised prior to PC = 00000B61 DBG>
DEPENDENTS_EXCEPTIONイベントの例(Ada)
Adaプログラムの場合,DEPENDENTS_EXCEPTIONイベントが起こると,そのあとにデッドロックが続くことがよくあります。 次に例を示します。
. . . break on ADA event DEPENDENTS_EXCEPTION Task %TASK 2 may await dependent tasks because of this exception: %ADA-F-EXCCOP, Exception was copied at a "raise;" or "accept" -ADA-F-EXCEPTION, Exception SOME_ERROR -ADA-F-EXCRAIPRI, Exception raised prior to PC = 00000B61 DBG>
RENDEZVOUS_EXCEPTIONイベントの例(Ada)
Adaプログラムの場合,RENDEZVOUS_EXCEPTIONイベントを指定しておけば, 制御がランデブを離れる前に(例外情報が呼び出しタスクにコピーされて失われる前に) その例外を見ることができます。次に例を示します。
. . . break on ADA event RENDEZVOUS_EXCEPTION Exception is propagating out of a rendezvous in task %TASK 2 %ADA-F-CONSTRAINT_ERRO, CONSTRAINT_ERROR -ADA-I-EXCRAIPRI, Exception raised prior to PC = 00000BA6 DBG>
/EVENT修飾子によって設定されたブレークポイントまたはトレースポイントを取り消すには,CANCEL BREAK/EVENT またはCANCEL TRACE/EVENTコマンドを使用します。SET コマンドのときとまったく同じように,CANCELコマンドにイベント修飾子とオプションのタスク式を指定します。 ただし, WHEN句やDO句は指定しません。
タスキング・プログラム用のデバッガ初期化ファイルに,イベント・ブレークポイントとトレースポイントを設定したいことがあります。 次に例を示します。
SET BREAK/EVENT=ACTIVATING SET BREAK/EVENT=HANDLED DO (SHOW CALLS) SET BREAK/EVENT=ABORT_TERMINATED DO (SHOW CALLS) SET BREAK/EVENT=EXCEPTION_TERM DO (SHOW CALLS) SET BREAK/EVENT=TERMINATED
次の各項では,タスク・デバッグに関係する次の補足事項について説明します。
デッドロックとは,あるタスク・グループ内の各タスクが中断されて, そのグループ内のどれか別のタスクが実行されないかぎり,グループ内のどのタスクも実行を再開できないエラー状態のことです。 デッドロックは, タスキング・プログラムでよく起こるエラーです。WHILE文を使用するプログラムでは無限ループがよく起こるエラーであるのと同様です。
デッドロックは簡単に検出できます。この状態のプログラムは実行を中断しているように見えます。 デバッガの制御下で実行しているプログラムがデッドロックを起こしたときには,Ctrl/C を押します。そのデッドロックが中断され, デバッガのプロンプトが表示されます。
通常は,SHOW TASK/ALLコマンド(第17.4 節を参照)かSHOW TASK/STATE=SUSPENDEDコマンドが役立ちます。プログラム内の中断しているタスクとその理由が示されるからです。 画面モードでデバッグしているときは,SET TASK/VISIBLE %NEXT_TASK コマンドがたいへん便利です。 これを使用すれば,すべてのタスクを調べ,各タスクが実行しているコード( 実行が停止しているコードを含む)を表示できるからです。
SHOW TASK/FULLコマンドでは,ランデブ情報,エントリ呼び出し情報, エントリ索引値などのタスク状態についての詳しい情報が得られます。SET BREAK/EVENT コマンドやSET TRACE/EVENTコマンド(第17.6.4項を参照)では, デッドロックを引き起こす可能性がある記憶位置かその近くにブレークポイントやトレースポイントを設定できます。SET TASK/PRIORITY コマンドとSET TASK /RESTOREコマンドでは,まったく実行されない低優先順位のタスクがデッドロックを引き起こしているのかどうかが分かります。
表 17-9に,さまざまなタスクのデッドロック状態と, その原因の診断に役立つと思われるデバッガ・コマンドの一覧を示します。
デッドロック状態 | デバッガ・コマンド |
---|---|
自己呼び出しデッドロック(タスクが自分自身のエントリの1 つを呼び出す) | SHOW TASK/ALL SHOW TASK/STATE=SUSPENDED SHOW TASK/FULL |
循環呼び出しデッドロック( あるタスクが別のタスクを呼び出し,呼び出されたタスクが最初のタスクを呼び出す) | SHOW TASK/ALL SHOW TASK/STATE=SUSPENDED SHOW TASK/FULL |
動的呼び出しデッドロック( 一連のエントリ呼び出しが循環し,そのうちの少なくとも1つがループ内の時限または条件付きエントリ呼び出しである) | SHOW TASK/ALL SHOW TASK/STATE=SUSPENDED SHOW TASK/FULL |
例外によって生じるデッドロック( 例外によって,タスクがそのエントリ呼び出しの1つに応えられないまたは例外の通知が依存タスクを待たなければならない) | SHOW TASK/ALL SHOW TASK/STATE=SUSPENDED SHOW TASK/FULL SET BREAK/EVENT=DEPENDENTS_EXCEPTION (Adaプログラムの場合) |
エントリ索引に対する実行時の計算間違い,when 条件,およびselect文内のdelay文によるデッドロック | SHOW TASK/ALL SHOW TASK/STATE=SUSPENDED SHOW TASK/FULL EXAMINE |
エントリが間違った順番で呼び出されたためのデッドロック | SHOW TASK/ALL SHOW TASK/STATE=SUSPENDED SHOW TASK/FULL |
優先順位の低いタスクによって設定される変数をフラグとして使用するが, それより優先順位の高いタスクがいつもレディ状態のため優先順位の低いタスクがまったく実行できなくて生じる, 変数の変更待ちデッドロック | SHOW TASK/ALL SHOW TASK/STATE=SUSPENDED SHOW TASK/FULL SET TASK/PRIORITY SET TASK/RESTORE |
タスキング・プログラムの場合,ある種の状況では検出されないスタック・ オーバフローが起こり,予期しない処理が行われることがあります。 タスク・スタック・オーバフローについての詳しい説明は,DEC AdaかDECthreadsのマニュアルを参照してください。 デバッガによって自動的に次のスタック・ チェックが行われるので,スタック・ オーバフローの問題の原因を探り出すのに役立ちます。スタック・ポインタが境界を越えている場合は, エラー・メッセージが表示されます。
次のエラー・メッセージ例は,スタック・チェックによってエラーが見つかったときに発行されるものです。 たとえスタックがまだオーバフローしていなくても, スタックの大半が使用し尽くされているときには,警告メッセージが発行されます。
warning: %TASK 2 has used up over 90% of its stack SP: 0011194C Stack top at: 00111200 Remaining bytes: 1868 error: %TASK 2 has overflowed its stack SP: 0010E93C Stack top at: 00111200 Remaining bytes: -10436 error: %TASK 2 has underflowed its stack SP: 7FF363A4 Stack base at: 001189FC Stack top at: 00111200
スタックのオーバフローに続いてスタックのアンダフローが起こることがあります。 その経過は次のとおりです。タスク・スタックがオーバフローしてスタック・ ポインタが上部保護領域を指したままでいるとき,オペレーティング・ システムはACCVIO状態をシグナル通知しようとします。しかし上部保護領域にはACCVIO のシグナル引数を書き込めないので,オペレーティング・ システムはスタックの別の場所を探します。つまり,フレーム・ ポインタとスタック・ポインタがメイン・プログラムのスタック領域の基底を指すようにしてシグナル引数を書き込み, プログラム・カウンタを変更してイメージを強制終了します。
このときタイム・スライスASTかその他のASTが発生すると,別のタスクの実行が再開し, しばらくの間は正常でないままプログラムが続行することがあります。 スタックがオーバフローしたタスクは,メイン・プログラムのスタックを使用し, 重ね書きすることがあります。デバッガのスタック・ チェックは,このような状態を検出するのに役立ちます。オペレーティング・ システムによってスタックの規定外の箇所に書き込みをされたタスク内の命令をステップ実行すれば, またはそのときにSHOW TASK/ALLコマンドを使用すれば, デバッガからスタック・アンダフロー・メッセージが発行されます。
デバッグ・セッション中にプログラムの実行やデバッガ・コマンドに割り込むには,Ctrl/C を押すのが望ましい方法です。Ctrl/Cを押せば制御はデバッガに戻りますが,Ctrl/Y を押せば制御はDCLレベルに戻ります。
Ctrl/Yを押してタスク・デバッグ・セッションに割り込むと,DEBUGコマンドを使用してDCL レベルでデバッガを開始するときに問題が生じることがあります。 そのような場合は,メイン・プログラムのソース・コードの先頭に次の2 行を挿入して,DEC Adaの定義済みパッケージCONTROL_C_ INTERCEPTIONの名前を指定してください。
with CONTROL_C_INTERCEPTION; pragma ELABORATE(CONTROL_C_INTERCEPTION);
このパッケージについての詳しい説明は,DEC Adaのマニュアルを参照してください。
[ 前のページ ]
[ 次のページ ]
[ 目次 ]
[ 索引 ]
[ DOC Home ]