[ 前のページ ] [ 次のページ ] [ 目次 ] [ 索引 ] [ DOC Home ]

17 タスキング・プログラムのデバッグ

本章では,タスキング・プログラム(マルチスレッド・プログラムとも呼ぶ) に固有のデバッガ機能について説明します。タスキング・プログラムは1 つのプロセス内に複数のタスクまたは実行スレッドを持っており,次のものを含んでいます。

デバッガで使用するタスクという用語は制御の流れのことであり, 言語や実現方法とは関係ありません。デバッガのタスキング・サポートは, 上記のようなプログラムすべてに適用されます。

本章では,DECthreads固有か言語固有の情報にはそのことを明記します。 第17.1節にDECthreads用語とAdaのタスキング用語の対応表を示します。

本章の機能を使用すれば,次のような処理を行うことができます。

これらの機能を使用するときには,同じタスキング・プログラムを実行してもそのときの状況によっては動作がデバッガにより変更されることがあるので注意してください。 たとえば,現在アクティブなタスクの実行をあるブレークポイントで中断しているとき, 入出力(I/O)の終了によるPOSIX 信号か非同期システム・トラップ(AST)が届いた場合は,ユーザの続行指示後ただちにその他のタスクが適格になることがあります。

DECthreadsやPOSIXスレッドについての詳しい説明は, 『Guide to DECthreads』を参照してください。Adaタスクについての詳しい説明はDEC Ada のマニュアルを参照してください。

マルチプロセス・プログラム(2つ以上のプロセスに分けて実行されるプログラム) のデバッグについては第15章を参照してください。

17.1 DECthreads用語とAda 用語の対応表

表 17-1にDECthreadsとAdaの用語とその意味の対応を示します。

表 17-1 DECthreads用語とAda用語の対応

DECthreads用語 Ada用語 意味
スレッド タスク 同じプロセス内の制御の流れ
スレッド・オブジェクト タスク・オブジェクト 制御の流れを表すデータ項目
オブジェクト名または式 タスク名または式 制御の流れを表すデータ項目
開始ルーチン タスク本体 制御の流れに従って実行されるコード
該当なし 親タスク 親タスクの制御の流れ
該当なし 依存タスク なんらかの親タスクに制御される子タスクの制御の流れ
同期化オブジェクト(ミューテクス, 条件変数) ランデブ構造(エントリ呼び出しやaccept 文など) 制御の流れを同期化する方法
スケジューリング方針およびスケジューリング優先順位 タスク優先順位 実行のスケジューリング方法
警告処理 abort 文 制御の流れの取り消し方法
スレッド状態 タスク状態 実行の状態( 待ち,レディ,実行中,終了)
スレッド作成属性( 優先順位,スケジューリング方針など) プラグマ パラレル・エンティティの属性

17.2 タスキング・プログラムの例

次の各項では,タスキング・プログラムのデバッグ時によく起こるエラーを含んでいるタスキング・ プログラムの例を示します。

本章のその他の例は,これらのプログラムを引用したものです。

17.2.1 Cのマルチスレッド・プログラムの例

例 17-1はマルチスレッドのCのプログラムです。 条件変数の使用法が間違っているのでブロッキングを起こします。

例のあとに説明が続いています。その説明のあとに,デバッガを使用してスレッドの相対的な実行を制御することによってブロッキングを診断する方法を示しています。

例 17-1では,初期スレッドにより, 計算作業を行う2 つのワーカ・スレッドが作成されます。これらのワーカ・ スレッドの作成後にSHOW TASK/ALLコマンドを実行すれば,それぞれが1 つのスレッドに対応する4つのタスクが表示されます。第17.4節にSHOW TASK コマンドの使用法が説明されています。

例 17-1では,ワーカ・スレッドのパスの行3893 に同期化点(条件待ち)が設けられています。行3877から始まるコメントは, このような直接的な呼び出しは間違ったプログラミング方法であることを示したうえで, 正しいコーディング方法を示しています。

このプログラムを実行すると,ワーカ・スレッドが大量の計算を行っているときに初期スレッドが条件変数をブロードキャストします。 条件変数をモニタしている最初のスレッドは初期スレッドのブロードキャストを検出してクリアし, 残りのスレッドを放置します。実行が妨げられ,プログラムは終了できなくなります。

例 17-1 Cのマルチスレッド・プログラムの例

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の番号に対応しています。

【1】
main()の最初のいくつかの文では,スレッドが使用する同期化オブジェクトと条件変数に対応する述語が初期化される。 それらの同期化オブジェクトは省略時の属性により初期化される。条件変数の述語は, 述語のまわりをループしているスレッドがループし続けるように初期化される。 プログラムのこの箇所でSHOW TASK/ALLを実行すれば,%TASK 1 が表示される。
【2】
ワーカ・スレッド%TASK 2 と%TASK 3が作成される。ここで作成された各スレッドは同じ起動ルーチン(worker_routine) を実行するので,pthread_createに対する同じ呼び出しを再使用できる。 ただし,異なるスレッドIDを格納するためにわずかな違いがある。 それらのスレッドは省略時の属性を使用して作成され,この例では使用されない引数を引き渡される。
【3】
条件変数に対応する述語がブロードキャストの準備のためクリアされる。 この結果,条件変数によってウェイクアップされるスレッドは正しくウェイクアップされ, 間違ってウェイクアップされることはない。述語をクリアすると,条件変数がブロードキャスト済みまたはシグナル通知済みとなっているので, 新しいスレッドが条件変数を待つこともなくなる。期待通りの効果が得られるかどうかは, 行3893の条件待ち呼び出しのコーディングが正しいかどうかによるが, この例のコーディングは間違っている。
【4】
初期スレッドはほとんどすぐにブロードキャスト呼び出しを実行するので, どのワーカ・スレッドもまだ条件待ちをしていない。ブロードキャストにより, その時点でその条件変数を待っているすべてのスレッドがウェイクアップされる。

プログラマは,ブロードキャスト時にすべてのスレッドが条件変数を待っているようにするか, またはブロードキャストがすでに起こったことを対応する述語で明らかにすることによって, そのブロードキャストが確実に認識されるようにしなければならない。 このような方法は,この例では意図的に省いている。

【5】
初期スレッドは,ワーカ・スレッドがどちらも正しく終了したことを確かめるために, 両者を結合しようとする。
【6】
ワーカ・スレッドがworker_routineを実行すると, 大量の計算に時間がかかる。そのため初期スレッドは,どちらのワーカ・ スレッドも条件変数を待つ準備ができていないときにその条件変数をブロードキャストする。
【7】
次にワーカ・スレッドはpthread_cond_wait 呼び出しを実行し,必要に応じて呼び出しのまわりでロックを行う。 両方のワーカ・スレッドがブロードキャストを検出できなくてブロックするのはこの箇所である。 そのときにSHOW TASK/ALLコマンドを入力すれば, 両方のワーカ・スレッドが条件変数を待っていることが分かる。 このようにプログラムがデッドロック状態になったときに制御をデバッガに戻すには,Ctrl/C を押さなければならない。

デバッガを使用すればスレッドの相対的な実行を制御することにより,例 17-1 のような問題を診断することができます。 この例の場合は,初期スレッドの実行を中断してワーカ・スレッドに計算を終了させ, ワーカ・スレッドがブロードキャスト時に条件変数を待っているようにできます。 その手順は次のとおりです。

  1. デバッグ・セッションの開始時に,ブロードキャストの直前で初期スレッドの実行が中断するよう, 行3836にブレークポイントを設定する。

  2. 初期スレッドを実行しワーカ・スレッドを作成するGOコマンドを入力する。

  3. すべてのスレッドの実行を中断するこのブレークポイントで, SET TASK/HOLD %TASK 1コマンドによって初期スレッドを保留する。

  4. ワーカ・スレッドが実行を続けるようにGOコマンドを入力する。 初期スレッドは保留され,実行できない。

  5. ワーカ・スレッドが条件変数をブロックしているときは,その時点でCtrl/C を押せば制御はデバッガに戻る。SHOW TASK/ALLコマンドを実行すれば, 両方のワーカ・スレッドが条件待ち副次状態で中断していることが示される。 示されない場合は,それらのワーカ・スレッドを実行するGO コマンドを入力し,Ctrl/Cを押してからSHOW TASK/ALL を入力する。両方のワーカ・スレッドが条件待ち副次状態になるまでこの手順を繰り返す。

  6. 最初にSET TASK/NOHOLD %TASK 1コマンド,次に初期スレッドが実行を再開してブロードキャストを行うように,GO コマンドを入力する。 これで,ワーカ・スレッドは結合し正常終了する。

17.2.2 Adaのタスキング・プログラムの例

例 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つのタスクが作成されます。

例 17-2 Adaのタスキング・プログラムの例

 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の番号に対応しています。

【1】
すべてのAdaライブラリ・パッケージ(この場合はTEXT_IO) の作成が終わると,メイン・プログラムが自動的に呼び出されてその宣言部分の作成が開始される( 行5〜82)。
【2】
この例では, 実行のつど同じ処理が行われるように,タイム・スライス機能( 第17.5.2項を参照)は使用していない。 プラグマTIME_SLICEの値が0.0になっているのは,プロシージャTASK_EXAMPLE のためにタイム・スライス機能を禁止する必要があることを示している。

VAXプロセッサでは,プラグマTIME_SLICEを省略するか値0.0 を指定すると,タイム・スライス機能は禁止される。

Alphaプロセッサでは,タイム・スライス機能を禁止するためにプラグマTIME_SLICE(0.0) を使用しなければならない。

【3】
タスク・オブジェクトFATHERが作成され,%TASK 2と指定されたタスクが作成される。FATHER にはプラグマPRIORITYがないので, 省略時の優先順位が与えられる。FATHER (%TASK 2)は中断状態で作成され,Ada の規則に従ってメイン・プログラムの文部分が開始されて初めて起動されます( 行83)。行29〜81のタスク本体の作成では,FATHER_TYPE型のタスクが実行する文が定義されている。
【4】
タスクFATHERはタスクCHILD を宣言する(行32)。1つのタスクは,1つのタスク・オブジェクトであり, なにか1つのタスク型を表す。タスクCHILDが作成され,起動されるのは,FATHER が起動されてからである。
【5】
非同期システム・ トラップ(AST)を引き起こすのは,このTEXT_IOの一連のPUT_LINE 文だけである。入出力(I/O)の終了によりASTが実行要求される。
【6】
タスクのFATHERは,メイン・プログラムが待っているときに並行して起動される。FATHER にはプラグマPRIORITYがないので,省略時の優先順位7 を与えられる(省略時の優先順位については『DEC Ada Run-Time Reference Manual』を参照)。FATHERの起動は行29〜44で作成される。

起動されたタスクFATHERは,タスクCHILDが起動され,%TASK 3を指定されたタスクが作成されるのを待つ。CHILD は行38で1つのエントリ呼び出しを実行し, そのエントリが受け付けられないのでデッドロックになる(第17.7.1項を参照)。

タイム・スライス機能が禁止され,優先順位の高い実行可能なタスクがないので,FATHER は起動後も行47のACCEPT文でブロックされるまで実行される。

【7】
タスクMOTHERが定義され,%TASK 4と指定されたタスクが作成される。 プラグマPRIORITYにより,MOTHERには優先順位6が与えられる。
【8】
タスクMOTHERが起動し,行91を実行する。起動後, メイン・プログラム(%TASK 1)の実行再開が可能になる。%TASK 1は省略時の優先順位が7 であり,MOTHERの優先順位より高いので,メイン・プログラムの実行が再開される。
【9】
メイン・プログラムとタスクFATHER の最初のランデブ。この後,FATHERは行58のTARMINATO文のSELECT で中断される。
【10】
FATHERとの3回目のランデブでは,FATHER は行67でSOME_ERRORという例外を発生させる。ハンドラは行72でその例外を捉え, 中断しているタスクCHILDを強制終了してから,再び例外を発生させる。 その後,FATHERは終了する。
【11】
delay文で指定されたループにより, 制御が行122に到達するときにはFATHERは終了するのに十分なほど先まで実行されている。
【12】
このエントリ呼び出しにより,MOTHER は行93のランデブ待ちを解除される。MOTHERはそのaccept 文(その他の文は含まない)を実行し,ランデブは終了する。すると,優先順位が6 にすぎないMOTHERは行94で制御を奪われる。
【13】
メイン・ プログラム(%TASK 1)はMOTHERとのランデブ後,行127〜129を実行する。 メイン・プログラムは行129で,自分のすべての依存タスクの終了を待たなければならない( 第17.6.4項を参照) 。メイン・プログラムが行129に到達するとき,まだ終了していないタスクはMOTHER だけである。MOTHERは,行97の文が実行されるまでは終了できない。MOTHER は行98で実行を終了する。すべてのタスクが終了したので, メイン・プログラムは実行を終了する。メイン・プログラムから制御が戻されて, コマンド行インタプリタの実行が再開される。

17.3 デバッガ・コマンドによるタスクの指定

タスクとは,その他のタスクと並行して実行される要素です。 タスクには固有のタスクID(第17.3.3 項を参照),独立したスタック,および独立したレジスタ・セットが与えられます。

アクティブ・タスクと可視タスクの現在の定義により,タスク操作のコンテキストが決まります。 第17.3.1 項を参照してください。

デバッガ・コマンドにタスクを指定するときには,次のいずれかの形式で指定できます。

17.3.1 アクティブ・タスクと可視タスクの定義

アクティブ・タスクとは,STEP,GO,CALL,またはEXITコマンドを実行したときに起動されるタスクです。 プログラムをデバッガの制御下に置くと, 最初はアクティブ・タスクの中で実行が中断されます。デバッグ・セッション中にアクティブ・ タスクを変更するにはSET TASK/ACTIVEコマンドを使用します。


注意
SET TASK/ACTIVEコマンドは, DECthreads経由で実行するタスキング,DECthrea ds(OpenVMS AlphaシステムとVAX システムの両方で)とAda(OpenVMS Alphaシステムで)の両方で動作しません。DECthreads で照会型のアクションを行うときは,SET TASK/ACTIVEコマンドの代わりに,SET TASK/VISIBLEコマンドを使用します。 特定のスレッドでステップを制御したいときは,ブレークポイントを適切な位置に配置します。

次のコマンドでは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節を参照してください。

17.3.2 Adaのタスキングの構文

タスクを宣言するには,単一タスクを宣言するか,またはあるタスク型のオブジェクトを宣言します。 次に例を示します。

     -- タスク型の宣言。
     --                                   
     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節を参照してください。

17.3.3 タスクID

タスク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.3.4 タスク組み込みシンボル

表 17-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)

17.3.4.1 呼び出す側のタスクのシンボル(Ada専用)

シンボル%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 になります。呼び出す側がタスクでないからです。

17.4 タスク情報の表示

プログラム内のタスクの情報を表示するには,SHOW TASKコマンドを使用します。

SHOW TASKコマンドでは,存在している(終了していない)タスクの情報が表示されます。 省略時の設定では,可視タスクの情報が1行だけ表示されます。

第17.4.1項第17.4.2項には, それぞれ,SHOW TASK コマンドによって表示されるDECthreadsタスクとAdaタスクの情報が説明されています。

17.4.1 DECthreadsタスクのタスク情報の表示

SHOW TASKコマンドでは,プログラム内に現存しているすべてのタスクの情報が表示されます( 例 17-3を参照) 。

例 17-3 DECthreadsタスクに対してSHOW TASK/ALL を実行したときの表示例

【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の番号に対応しています。

【1】
タスクID(第17.3.3項を参照)。 アクティブ・タスクには左端の欄にアスタリスク(*) が付けられる。
【2】
タスクの現在の状態(表 17-3 を参照)。RUN (RUNNING)状態のタスクがアクティブ・ タスクである。表 17-3には, プログラムの実行中にどの状態に移ることができるかが示されている。
【3】
タスクがSET TASK/HOLDコマンドによって保留されているかどうか。 タスクの保留については第17.5.1項を参照。
【4】
タスクの優先順位。
【5】
タスクの現在の副次状態。副次状態はあるタスク状態を引き起こした原因を推定するのに役立つ。 表 17-4を参照。
【6】
タスク( スレッド)オブジェクトのデバッガのパス名,または,デバッガがタスク・ オブジェクトをシンボル化できない場合はタスク・オブジェクトのアドレス。

表 17-3 一般的なタスクの状態

タスクの状態 説明
RUNNING タスクは現在プロセッサで実行中である。 これがアクティブ・タスクである。この状態のタスクが移ることができるのは,READY, SUSPENDED, TERMINATED のいずれかの状態である。
READY タスクは実行適格であり, プロセッサが使用可能になるのを待っている。この状態のタスクが移ることができるのはRUNNING 状態だけである。
SUSPENDED タスクは中断している。 つまり,プロセッサが使用できるのを待っているのではなく,あるイベントを待っている。 たとえば,タスクは作成されてから起動されるまで中断状態に留まる。 この状態のタスクが移ることができるのは, READY状態またはTERMINATED状態だけである。
TERMINATED タスクは終了している。この状態のタスクは, ほかの状態に移ることはできない。

表 17-4 DECthreadsタスクの副次状態

タスクの副次状態 説明
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タスクの例でこのコマンドを実行した場合の出力を示します。

例 17-4 DECthreadsタスクに対してSHOW TASK/FULL を実行したときの表示例

【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の番号に対応しています。

【1】
タスク情報の種別を示す。
【2】
なんらかの異常についての掲示板型の情報。
【3】
次に実行される箇所を示すPC 値と起動ルーチン。
【4】
タスク・スケジューリングの方針。
【5】
スタック記憶域の情報。
【6】
タスク・スタックの上限アドレスと下限アドレス。
【7】
タスク(スレッド)制御ブロック情報。タスク値はタスク制御ブロックの16 進表記アドレス。
【8】
タスクが使用する記憶域の合計。タスク制御ブロック・ サイズ,予約バイト数,上部保護領域サイズ,記憶域サイズを合計したもの。

図 17-1にタスク・スタックを示します。

図 17-1 タスク・スタック図

SHOW TASK/STATISTICSコマンドでは,プログラム内のすべてのタスクについての統計情報が報告されます。 例 17-5には,DECthreads タスクのプログラム例に対してSHOW TASK/STATISTICS/FULL コマンドを実行したときの出力が示されています。 この情報により,プログラムの性能を測定できます。 スケジューリング(コンテキスト・スイッチとも呼ぶ)の合計回数が多いほど, タスキング・オーバヘッドは大きくなります。

例 17-5 DECthreadsタスクに対してSHOW TASK/STAT/FULL を実行したときの表示例(VAX システムの例)

task statistics
    Total context switches:              0
    Number of existing threads:          0
    Total threads created:               0
DBG>

17.4.2 Adaタスクのタスク情報の表示

SHOW TASK/ALLコマンドでは,プログラム内に現存しているすべてのタスクの情報, つまりタスク自体が作成されてからその親がまだ終了していないすべてのタスクの情報が表示されます( 例 17-6を参照)。

例 17-6 Adaタスクに対してSHOW TASK/ALLを実行したときの表示例

【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の番号に対応しています。

【1】
タスクID(第17.3.3項を参照)。 アクティブ・タスクには左端の欄にアスタリスク(*) が付く。
【2】
タスク優先順位。Adaの優先順位は0〜15。

VAXプロセッサで作成されるタスクは省略時の設定である優先順位7 が割り当てられる。ただし,それ以外の優先順位がプラグマPRIORITY で指定されている場合は,その優先順位が割り当てられる。

Alphaプロセッサで作成されるタスクは, タイム・スライス機能が使用不能ならば,省略時の設定である優先順位7 が割り当てられる。タイム・スライス機能が使用可能ならば, プラグマPRIORITYが指定されていないかぎり,適当な中間の値が優先順位として割り当てられる。

【3】
タスクがSET TASK/HOLDコマンドによって保留中かどうかを示す。 タスクの保留については,第17.5.1項を参照。 タスクの保留には,プログラムの以降の実行が許可されていれば, タスクの状態遷移の制限が伴う。
【4】
タスクの現在の状態(表 17-3 を参照)。RUN (RUNNING)状態のタスクがアクティブ・タスク。 表 17-3には,プログラムの実行中に移る可能性のある状態が示されている。
【5】
タスクの現在の副次状態。 副次状態は,あるタスク状態を引き起こした原因を推定するのに役立つ。 表 17-5を参照。
【6】
タスク・オブジェクトのデバッガのパス名,または,デバッガがタスク・ オブジェクトをシンボル化できない場合はタスク・オブジェクトのアドレス。

表 17-5 Adaタスクの副次状態

タスクの副次状態 説明
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 タスク例に対してこのコマンドを実行したときの出力が示されています。

例 17-7 ADAタスクに対してSHOW TASK /FULLを実行したときの表示例

【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の番号に対応しています。

【1】
タスク情報の種別を示す。
【2】
ランデブ情報。呼び出しタスクの場合は,そのタスクが登録されているキューの各エントリが一覧表示される。 呼び出されるタスクの場合は, 実行されるランデブの種類が表示されるほか,そのタスクを待つキューのどれかのエントリに現在登録されている呼び出しタスクが一覧表示される。
【3】
タスクのコンテキスト情報。
【4】
タスク制御ブロック情報。 「Task value」の右の16進数は,タスク制御ブロックのアドレスである。
【5】
スタック記憶域の情報。
【6】
タスク・スタックのスタック・アドレス。
【7】
タスクが使用する記憶域の合計。 タスク制御ブロックサイズ,予約領域バイト数, 上部保護領域サイズ,および記憶域サイズの合計である。

SHOW TASK/STATISTICSコマンドでは,プログラム内のすべてのタスクについての統計情報が報告されます。 例 17-8は,VAX プロセッサでAdaタスキング・ プログラム例に対してSHOW TASK/STATISTICS/FULLコマンドを実行したときの出力です。 この情報により,プログラムの性能を測定できます。 スケジューリング(コンテキスト・スイッチとも呼ぶ)の総数が多いほど, タスキング・オーバヘッドは大きくなります。

例 17-8 Adaタスクに対してSHOW TASK/STATISTICS/FULLを実行したときの表示例(VAXプロセッサの例)

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>

17.5 タスク特性の変更

デバッグ中にタスクの特性やタスキング環境を変更するには,次表の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コマンドの説明を参照してください。

17.5.1 タスクの保留によるタスク・スイッチの制御

タスク・スイッチにより,プログラムのデバッグが複雑になります。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コマンドを使用します。

17.5.2 タイム・スライス機能を使用するプログラムのデバッグ(VAX のみ)

タイム・スライス機能を使用するタスキング・プログラムのデバッグは複雑です。 タイム・スライス機能によってタスクの相対的な動作が非同期になるからです。 タイム・スライス機能を使用しない場合,タスクの実行はタスクの優先順位だけで決まります。 タスク・スイッチは予測可能なので, 実行のたびにプログラムの同じ動作を繰り返すことができます。タイム・ スライス機能を使用する場合もタスクの優先順位によってタスク・スイッチが行われますが, 指定期間は同じ優先順位の複数のタスクが交互に実行されます。 したがって,タイム・スライス機能があれば各タスクは互いにいっそう独立して実行されるようになります。 そのため,タイム・スライス機能を使用するプログラムは, 実行するたびに同じ動作を繰り返さないことがあります。

SET TASK/TIME_SLICE=tコマンド(VAX Adaのみでサポート) を使用すれば,新しいタイム・スライスを指定したり,SET TASK/TIME_ SLICE=0.0と指定してタイム・スライス機能を禁止したりできます。したがって, タスキング・プログラムの実行を調整したり,タスクの実行順序に依存する問題を診断したりできます。


注意
SET TASK/TIME_SLICEコマンドは,VAX Ada のみでサポートされており,DECthre adsを使用したVAX Ada ではサポートされていません。サポートされていないコンテキストでコマンドを使用する場合, 次のエラー・メッセージが出されます。
     %DEBUG-E-NOTIMSLI, time slice modification
          not supported by this event facility

タイム・スライス機能とデバッガのウォッチポイントの実行とは,互いに影響を与えることに注意してください。 ウォッチポイントを設定すると, タイム・スライス間隔値はデバッガにより自動的に10.0秒に増加されることがあります。 タイム・スライス速度を遅くすることにより,発生を防げる問題があるからです。

17.6 実行の制御とモニタ

次の各項では,次の各機能の実行方法について説明します。

17.6.1 タスク依存およびタスク非依存のデバッガ・ イベントポイントの設定

イベントポイントとは,デバッガに制御を戻すために使用できるイベントです。 ブレークポイント,トレースポイント,ウォッチポイント, および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コマンドを実行すれば, タスク依存イベントポイントが設定されます。


/BRANCH
/CALL
/INSTRUCTION
/LINE
/RETURN
/VECTOR_INSTRUCTION (VAX専用)

これらのコマンドでこれらの修飾子を使用しないで設定するイベントポイントおよび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.6.2 DECthreadsタスキング構造へのブレークポイントの設定

ブレークポイントをスレッド起動ルーチンに設定することは可能です。そのようなブレークポイントは, 起動ルーチンの実行開始直前に検出されます。 例 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.6.3 Adaタスク本体,エントリ呼び出し, およびaccept 文へのブレークポイントの設定

タスク本体にブレークポイントを設定するには,次のどちらかの構文に従ってタスク本体を指定します( 第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文にブレークポイントかトレースポイントを設定すれば, 呼ぶ側,呼ばれる側のタスクの実行をモニタできます。


注意
Adaタスクのエントリ呼び出しは, サブプログラム呼び出しと同じではありません。タスク・エントリ呼び出しはキューに登録されるので, すぐ実行されるとは限らないからです。STEP コマンドを使用して実行をタスク・エントリ呼び出しに移しても, 期待通りの結果が得られないことがあります。

ブレークポイントやトレースポイントの設定に適する箇所は,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)

17.6.4 タスク・イベントのモニタ

SET BREAK/EVENTコマンドとSET TRACE/EVENTコマンドを使用すれば,タスク・ イベントと例外イベントによって検出されるブレークポイントおよびトレースポイントを設定できます。 たとえば,次のコマンドで設定するトレースポイントは, タスクCHILDか%TASK 2がRUN状態に移るときに検出されます。

     DBG> SET TRACE/EVENT=RUN CHILD,%TASK 2

あるイベントの結果,ブレークポイントかトレースポイントが検出されると, デバッガはそのイベントを識別し,追加情報を与えます。

次の各表に,SET BREAK/EVENTコマンドとSET TRACE/EVENTコマンドに指定できるイベント名キーワードの一覧を示します。

表 17-6 下位レベルの汎用タスクのスケジューリング・ イベント

イベント名 機能
RUN タスクが実行する直前に検出される。
PREEMPTED RUN状態にあるタスクが強制的にREADY 状態に移される直前に検出される( 表 17-3 を参照)。
ACTIVATING タスクが実行を開始する直前に検出される。
SUSPENDED タスクが中断される直前に検出される。

表 17-7 DECthreads依存イベント

イベント名 機能
HANDLED あるTRYブロックで例外が処理される直前に検出される。
TERMINATED タスクが終了する直前に検出される(警告や例外による場合を含む) 。
EXCEPTION_TERMINATED タスクが例外によって終了する直前に検出される。
FORCED_TERM タスクが警告処理によって終了する直前に検出される。

表 17-8 Ada固有のイベント

イベント名 機能
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イベントの例

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

17.7 タスク・デバッグについての補足

次の各項では,タスク・デバッグに関係する次の補足事項について説明します。

17.7.1 デッドロック状態になるプログラムのデバッグ

デッドロックとは,あるタスク・グループ内の各タスクが中断されて, そのグループ内のどれか別のタスクが実行されないかぎり,グループ内のどのタスクも実行を再開できないエラー状態のことです。 デッドロックは, タスキング・プログラムでよく起こるエラーです。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に,さまざまなタスクのデッドロック状態と, その原因の診断に役立つと思われるデバッガ・コマンドの一覧を示します。

表 17-9 Adaタスクのデッドロック状態とそれを診断するためのデバッガ・ コマンド

デッドロック状態 デバッガ・コマンド
自己呼び出しデッドロック(タスクが自分自身のエントリの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

17.7.2 デバッガによる自動スタック・チェック

タスキング・プログラムの場合,ある種の状況では検出されないスタック・ オーバフローが起こり,予期しない処理が行われることがあります。 タスク・スタック・オーバフローについての詳しい説明は,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コマンドを使用すれば, デバッガからスタック・アンダフロー・メッセージが発行されます。

17.7.3 AdaタスクをデバッグするときのCtrl/Yの使用

デバッグ・セッション中にプログラムの実行やデバッガ・コマンドに割り込むには,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 ]