プロセス / タスク管理機能では、 シングルユーザ / マルチプロセスのシステムを実現するために必要な各種の機能を提供している。
プロセスとはプログラムを OS が管理する単位であり、 1 つのマシン上に複数のプロセスが存在する。
タスクとはプログラムの実行単位であり、 1 つのプロセスには 1 つまたは複数のタスクが存在し、 優先度順および時分割のスケジューリングにより同時に実行される。
1 つのプロセスは基本的に下図に示すような独立したアドレス空間を持つ。
プロセスは、対象となる実行プログラムファイルを指定して生成され、 生成時に割り付けられるプロセス ID により識別される。 プロセス ID は、正の整数値であり、 その割り付け方法は若い番号から順番に割り付けられる。
プロセスが生成されると、 メインタスクが実行を開始する。 メインタスクによってサブタスクを起動することで、 1 つのプロセス内に複数のタスクが存在する状態になる。 つまり、プロセスには 1 つのメインタスクと 0 個以上のサブタスクが同時に存在する。
メインタスクとサブタスクを総称してタスクと呼ぶ。 タスクはタスクIDにより識別される。 タスクIDは正の整数となる。
システムの立上げ時に、まず初期プロセスが生成され、 初期プロセスが順次必要なプロセスを生成していくことになる。 自分が生成したプロセスを子プロセスと呼び、 自分を生成してくれたプロセスを親プロセスと呼ぶ ( 初期プロセスの親プロセスは存在しない )。 従って、システム全体としては、 初期プロセスをルートとする木構造のプロセス構造をとる。
あるプロセスが終了した場合には、 その子プロセスの親プロセスは終了したプロセスの親プロセスに入れ換り、 全体として木構造は保たれることになるが、 例外的に初期プロセスが終了した場合には、 その子プロセスの親プロセスは存在しない状態となる。
プロセスの状態として以下の 4 つの基本状態が定義される。
プロセスの状態は、メインタスクの状態である。
未生成状態 | (Non-Existent) | -- プロセスは生成されていない状態 |
実行可能状態 | (Ready) | -- 実行可能でディスパッチ待ち状態 |
実行状態 | (Run) | -- 実行中状態 |
待ち状態 | (Wait) | -- メッセージ、時間、入出力等の待ち状態 |
プロセスの各状態は各種のシステムコールや、 スケジューリング ( ディスパッチ、プリエンプト ) により以下のように遷移する。
プロセスの状態は、以下に示すデータとして取り出すことが可能である。
typedef struct { UW state; /* プロセス状態 */ W priority; /* 現在のプロセス優先度( 0 〜 255 ) */ W parpid; /* 親プロセスのプロセス ID */ } P_STATE;
プロセスの状態 ( state
) は以下の内容であり、
それぞれ "1" でその状態にあることを示す。
サブタスクも同等の状態を持ち、同様の状態遷移が行われる。
プロセスの終了により、すべてのタスクが終了する。 また、メインタスクの終了により、すべてのサブタスクが強制終了され、 プロセスの終了となる。サブタスクの終了は、プロセスの終了にはならない。
プロセスには、生成時に 0 〜 255 ( 0 が最高優先度 ) の優先度が与えられる。 この優先度はメインタスクの優先度となる。 プロセス優先度と言った場合、それはメインタスクの優先度と等価である。 各プロセスはその優先度により、下記の3つのグループに分類される。
また、サブタスクにもタスク生成時に優先度が与えられる。
各タスクは、その優先度に従ってスケジューリングが行なわれる。
厳密に優先度順にスケジューリングされ(0が最高優先度)、 同一優先度の場合は、 ラウンドロビン方式で平等にスケジューリングされる。
このグループ内全体でラウンドロビンスケジューリングが行なわれ、
優先度は相対的なスケジューリングの頻度を示す
(128が最高優先度) 。
従って、優先度が低いタスクでも必ず実行されることが保証される。
このグループ内全体でラウンドロビンスケジューリングが行なわれ、
優先度は相対的なスケジューリングの頻度を示す
(192が最高優先度)。
従って、優先度が低いタスクでも必ず実行されることが保証される。
実際のスケジューリングは、全体として以下のように行なわれる。
絶対優先度グループに属する実行可能状態のタスクがあれば、 その中の最高優先度のタスクを実行状態とし、 実行する。なければ、2. へ進む。
ラウンドロビングループ 1 に属する実行可能状態のタスクがあれば、 その中の相対優先度に従って、 選択されたタスクを実行状態とし、 実行する(最高優先度とは限らない)。 なければ、2. へ進む。
ラウンドロビングループ 2 に属する実行可能状態のタスクがあれば、 その中の相対優先度に従って、選択されたタスクを実行状態とし、 実行する(最高優先度とは限らない)。 なければ、スケジューリングを始めからやり直す。
通常、絶対優先度グループは、システムプロセスやリアルタイムプロセスに使用され、 一般のアプリケーションプロセスはラウンドロビングループ 1、または 2 を使用する。
一度生成されたプロセス / タスクの優先度の変更は、 同一グループ内でのみ可能であり、 グループが異なる優先度への変更はできない。
プロセスには、その実行環境として以下のような情報が保持されている。
プロセスを生成した場合(cre_prc)は、 生成された子プロセスの実行環境は以下のように設定される。
自分 / 親 / 子のプロセス ID | 自分 / 親のプロセス ID |
プロセスの優先度 | 生成時に指定した優先度 |
ユーザ情報 | 生成時の親プロセスのユーザ情報 |
現在の作業ファイル | 生成時の親プロセスの作業ファイル |
オープン中のファイル | 無し |
メッセージキュー | 空 |
ユーザ情報は、 そのプロセスを生成して使用しているユーザに関する情報であり、 以下に示す内容を持つ。
ユーザの名称であり、12 文字の名前の後に 2 文字分 ( 32 ビット ) の隠し名を付けたものである。 12 文字より少ない名前の場合は 0 がパッドされ、名前が存在しない場合は、14 文字がすべて 0 となる。
ユーザが所属する 4 つのグループの名称であり、 それぞれ 12 文字の名前の後に 2 文字分 ( 32 ビット) の隠し名を付けたものである。 12 文字より少ない名前の場合は 0 がパッドされ、 名前が存在しない場合は、14 文字がすべて 0 となる。
ユーザの特権レベルであり、0 〜 15 の範囲の値を取り、 0 が最高レベルとなる。
ネットワーク経由で他のマシンをアクセスする場合のユーザレベルで、 1 〜 15 の範囲の値を取り、 1 が最高レベルである。この場合、 ネットワークユーザレベルの 0 は適用されない。
ファイルを生成する場合のデフォールトのアクセスモード。
ユーザ情報は、 以下に示す構造体で定義され、 システムコールにより取出し / 設定が可能である。 ただし、隠し名を取り出すことはできず、 隠し名の部分には常に 0 が得られることになる。
typedef struct { TC usr_name[14]; /*ユーザ名(12文字+隠し名2文字)*/ TC grp_name1[14]; /*グループ名1(12文字+隠し名2文字)*/ TC grp_name2[14]; /*グループ名2(12文字+隠し名2文字)*/ TC grp_name3[14]; /*グループ名3(12文字+隠し名2文字)*/ TC grp_name4[14]; /*グループ名4(12文字+隠し名2文字)*/ W level; /*ユーザレベル(0〜15)*/ W net_level; /*ネットワークユーザレベル(1〜15)*/ } P_USER;
初期プロセスのユーザ情報は、当初はシステムで定義された固定的な内容を持つが、 その後、ユーザーが確定した時点で、実際のユーザ情報が設定されることになる。
プロセスの生成は、対象とするファイル、プロセスの優先度、 およびプロセスに渡すメッセージを指定することにより行なわれる。
指定したファイル内の最初の実行プログラムレコードの内容が生成するプロセスのプログラムコードとなる。 実行プログラムレコードは、先頭レコードでなければならない。
プロセスに渡すメッセージは以下のメッセージ構造体へのポインタで指定される。 これはプロセス間メッセージと同一の構造を持つ。
typedef struct { W msg_type; /*メッセージタイプ*/ W msg_size; /*メッセージサイズ(バイト数)*/ UB msg_body[n]; /*メッセージ本体(msg_size バイト)*/ } MESSAGE;
生成されたプロセスは以下に示す2つのどちらかの形式により、
メッセージを受け取ることができる ( ただし、形式-B は、実際にはライブラリとして実現される )。
MAIN()
および main()
からのリターンはプロセスの終了となり、
ext_prc()
による終了と同等である。
終了コードは、正常終了メッセージに設定され、親プロセスに通知される。
W MAIN (MESSAGE *msg) /* MESSAGE *msg; メッセージへのポインタ*/ { < プログラムの実行コード > return 終了コード; }
msg_type
に無関係にすべてのメッセージを受け取ることが可能。
W main (W ac, TC **argv) /* W ac; 文字列項目数*/ /* TC **argv; 文字列項目のポインタ配列へのポインタ*/ { < プログラムの実行コード > return 終了コード; }
生成時に指定したメッセージの msg_type = 0
の場合にのみ、
この形式が適用可能で、この場合は msg_body[]
は TNULL
で終了する
1 つの文字列と見なされる。
文字列は空白で区切られ、複数の項目に分解される。
プログラムへは、各項目の文字列へのポインタの配列として渡されることになる。
msg_body[]
が TNULL
で終了していない場合は、
最後の文字は TNULL
と見なされる。
この形式の場合は、生成時に指定されたメッセージの
msg_type ≠ 0
の時は、ac= 0, *argv=NULL
となり、
メッセージを受け取ることはできない。
main()
での引数の構造プロセスは複数のタスクで構成されるため、 各タスクが同時並行的に動作することができる。 タスクは、プログラムの流れに沿って実行されるが、 例外的に以下のハンドラ(関数)は非同期に割り込んで実行される。
メッセージ受信により非同期に実行される関数。
自プロセス内の例外発生により非同期に実行される関数。
これらの関数はいずれもプロセスの一部として、 そのプロセスのメモリ空間、および環境の下で実行され、 使用可能なシステムコール等の制限は特にない。 実行終了後は、割り込まれた位置に戻るか、 または任意の位置に直接ジャンプすることができる。
メッセージハンドラの詳細に関しては「1.2.3 メッセージハンドラ」を、 例外処理ハンドラの詳細に関しては「1.10 システム管理機能」を参照のこと。
また、プロセスはその実行時に以下のようなプロセス統計情報を得ることができる。
typedef struct { UW etime; /*累計経過時間 (秒単位)*/ UW utime; /*プロセスで費やした累計CPU時間*/ UW stime; /*システムで費やした累計CPU時間*/ W tmem; /*実行に必要とする全体のメモリサイズ*/ W wmem; /*現在割り付けられている実メモリサイズ*/ W resv[11]; /*予約*/ } P_INFO;
utime
と stime
は、プロセスに含まれる、
その時点で存在するすべてのタスクの合計時間となる。
したがって、それ以前に終了したタスクが費やした時間は含まれない。
utime
と stime
を合計したものが、
そのプロセスが費やした累積 CPU 時間となる。
typedef struct { UW state; /* プロセス状態 */ W priority; /* 現在のプロセス優先度( 0 〜 255 ) */ W parpid; /* 親プロセスのプロセス ID */ } P_STATE;
typedef struct { TC usr_name[14]; /* ユーザ名(12文字+隠し名2文字) */ TC grp_name1[14]; /* グループ名1(12文字+隠し名2文字) */ TC grp_name2[14]; /* グループ名2(12文字+隠し名2文字) */ TC grp_name3[14]; /* グループ名3(12文字+隠し名2文字) */ TC grp_name4[14]; /* グループ名4(12文字+隠し名2文字) */ W level; /* ユーザレベル(0 〜 15) */ W net_level; /* ネットワークユーザレベル(1〜15) */ } P_USER;
typedef struct { UW etime; /* 累計経過時間 (秒単位) */ UW utime; /* プロセスで費した累計CPU時間 */ /* (OS内での処理時間は除外する) */ /* (ミリ秒単位) */ UW stime; /* システムで費した累計CPU時間 */ /* (ミリ秒単位) */ W tmem; /* 実行に必要とする全体のメモリサイズ */ /* (バイト単位) */ W wmem; /* 現在割り付けられている実メモリサイズ */ /* (バイト単位) */ W resv[11]; /* 予約 */ } P_INFO;
#define TERM_NRM 0x0000 /* 指定プロセスのみの強制終了 */ #define TERM_ALL 0x0001 /* 子プロセスまで含めた強制終了 */
#define P_ABS 0x0000 /* 優先度の絶対指定 (≧0) */ #define P_REL 0x0001 /* 優先度の相対指定 */ #define P_TASK 0x0002 /* タスクを対象とする */
#define P_WAIT 0x2000 /* 待ち状態 */ #define P_READY 0x4000 /* 実行可能状態 */ #define P_RUN 0x8000 /* 実行状態 */
|
WERR cre_prc(LINK* lnk, W pri, MESSAGE* msg)
LINK* lnk 対象実身 W pri プロセス優先度 0 ≦ pri ≦ 255 任意の優先度 = -1 自プロセスと同じ優先度 MESSAGE* msg プロセス起動時メッセージ
>0 正常(生成したプロセス ID) <0 エラー(エラーコード)
指定した実身内の実行プログラムレコードを、 新しいプロセスとして生成する。 同時にメインタスクが生成され実行を開始する。
「1.1.6 プロセスの生成」を参照のこと。
ER_ACCES : ファイル(lnk)のアクセス権(E)がない。 ER_ADR : アドレス(lnk,msg)のアクセスは許されていない。 ER_BUSY : ファイル(lnk)は既に排他的にオープンされている為、 同時にファイルをオープンすることができなかった。 ER_IO : 入出力エラーが発生した。 ER_NOEXS : ファイル(lnk)は存在していない。 ER_NOFS : ファイル(lnk)の属するファイルシステムは接続されていない。 ER_NOMEM : メモリ領域が不足した。 ER_NOSPC : システムのメモリ領域が不足した(プロセス数が多すぎる)。 ER_PPRI : 優先度の値が範囲外である(-1,-0〜255 以外)。 ER_REC : ファイルにプログラムレコードは存在しない、 またはプログラムレコードの内容が異常である。 ER_SZOVR : プロセス起動メッセージのサイズがシステムの制限を越えた。
|
VOID ext_prc(W code)
W code プロセス終了コード
リターンしない
自プロセスを正常終了し、
指定した code
を含むプロセス正常終了メッセージを親プロセスに送信する。
自プロセスで使用中のファイル等のリソースは一部のリソース
( cre_sem
等オプションに DELEXIT
指定がないもの)を除き、
すべて自動的に解放される。
発生しない。
|
ERR ter_prc(W pid, W code, W opt)
W pid 対象プロセス ID > 0 任意のプロセス = 0 自プロセス(指定不可:エラー) = -1 親プロセス W code 強制終了コード W opt 強制終了属性 ( TERM_NRM ‖ TERM_ALL ) TERM_NRM 指定したプロセスのみの強制終了。 TERM_ALL 指定したプロセスおよびその全ての子孫のプロセスの強制 終了。親プロセスまたはさらにその親のプロセスを指定し た場合には、自プロセスも強制終了させられる。 この場合、指定したプロセスの子孫の強制終了メッセージ は送信されない。
=0 正常 <0 エラー(エラーコード)
指定したプロセスを強制終了し、
指定した code
を含むプロセス強制終了メッセージを指定したプロセスの親プロセスに送信する。
自プロセスより高いユーザレベルのプロセスは強制終了できない。
ER_SELF : 自プロセスを指定した(pid = 0または自プロセスのPID)。 ER_NOPRC : プロセス(pid)は存在していない。 ER_LEVEL : 自プロセスより高いユーザレベルのプロセスを指定した。 ER_PAR : パラメータが不正である(opt=TERM_NRM,TERM_ALL以外を指定した)。
|
WERR chg_pri(W id, W pri, W opt)
W id 対象プロセス ID またはタスク ID W pri 変更する優先度 W opt 優先度属性 ( P_ABS ‖ P_REL ) | [ P_TASK ] P_ABS 絶対指定:指定した優先度に変更。 P_REL 相対指定:(現在の優先度)+pri に変更。 T_TASK タスクを対象とする。
≧0 正常(変更後の優先度 0〜255) P_TASK 指定あり id のタスクの優先度 P_TASK 指定なし id のプロセスのメインタスクの優先度 <0 エラー(エラーコード)
指定したプロセス / タスクの優先度を変更する。
P_TASK
の指定がない場合 :
id = 0 自プロセス内の全タスクの優先度を変更する。 id = -1 親プロセス内の全タスクの優先度を変更する。 id > 0 id で指定したプロセス ID のプロセス内の全タスクの優先度を変更する。
P_TASK
が指定された場合
id = 0 自タスクの優先度を変更する。 id > 0 id で指定したタスク ID のタスクの優先度を変更する。 指定できるタスクは、自プロセス内のタスクのみである。
指定できる優先度の範囲は、 対象タスクが属するプロセスの現在の優先度グループ内となる。
ER_NOPRC : プロセス(id)は存在していない。 ER_ID : タスク(id)は存在していない。または、自プロセス内のタスクではない。 ER_PPRI : 優先度の値が範囲外である(新優先度は現在優先度のグループ外)。 ER_PAR : パラメータが不正である(opt=P_ABS,P_REL,P_TASK以外を指定した)。
|
WERR prc_sts(W pid, P_STATE* buff, TC* name)
W pid 対象プロセス ID > 0 任意のプロセス = 0 自プロセス = -1 親プロセス P_STATE* buff プロセス状態の格納領域 NULL 格納しない TC* name プロセス名(実身名)の格納領域(最大実身名+1文字分の領域) NULL 格納しない
>0 正常(指定プロセス ID) <0 エラー(エラーコード)
指定したプロセスの状態を取得する。
pid = 0, buf = NULL, name = NULL
として自プロセス ID の取得にも使用する。
ER_ADR : アドレス(buff,path)のアクセスは許されていない。 ER_NOPRC : プロセス(pid)は存在していない。
|
ERR chg_usr(P_USER* buff)
P_USER* buff 変更するユーザ情報
=0 正常 <0 エラー(エラーコード)
自プロセスのユーザ情報を指定した内容に変更する。 変更した内容は、それ以後生成した子プロセスに継承される。
本システムコールはシステムプロセスでのみ実行可能で、 一般のアプリケーションプロセスでは実行できない。
ER_ADR : アドレス(buff)のアクセスは許されていない。 ER_PAR : パラメータが不正である(ユーザ情報が不正)。
|
WERR get_usr(W pid, P_USER* buff)
W pid 対象プロセス ID > 0 任意のプロセス = 0 自プロセス = -1 親プロセス P_USER* buff ユーザ情報の格納領域 NULL 格納しない
>0 正常(指定プロセス ID) <0 エラー(エラーコード)
指定したプロセスのユーザ情報を取得する。 取り出したユーザー名およびグループ名 1 〜 4 の隠し名は常に 0 となり、 取り出すことはできない。
pid = 0, buf = NULL
として自プロセス ID の取得にも使用する。
ER_ADR : アドレス(buff)のアクセスは許されていない。 ER_NOPRC : プロセス(pid)は存在していない。
|
ERR get_inf(W pid, P_INFO* buff)
W pid 対象プロセス ID > 0 任意のプロセス = 0 自プロセス = -1 親プロセス P_INFO* buff 統計情報の格納領域
=0 正常 <0 エラー(エラーコード)
指定したプロセスの統計情報を取得する。
ER_ADR : アドレス(buff)のアクセスは許されていない。 ER_NOPRC : プロセス(pid)は存在していない。
|
WERR cre_tsk(FP entry, W pri, W arg)
FP entry サブタスク開始アドレス W pri サブタスク優先度 W arg サブタスク起動パラメータ
>0 正常(生成したサブタスク ID) <0 エラー(エラーコード)
自プロセス内のサブタスクを生成して実行する。
サブタスクの優先度は、自プロセスの優先度グループの範囲内でのみ指定できる。 サブタスクは以下の形式の関数として定義される。
VOID subtask(W arg) { /* arg は cre_tsk() で指定したパラメータ */ < サブタスクコード > /* タスク終了 */ ext_tsk(); }
サブタスクを return
で終了することはできない。
ER_ADR : アドレス(entry)が不正である。 ER_PPRI : 優先度(pri)が自プロセスの優先度グループの範囲を超えている。 ER_LIMIT : サブタスク数の制限を超えた。 ER_NOMEM : メモリー領域が不足した。
|
VOID ext_tsk()
自タスクを終了する。
メインタスクが終了した場合はプロセスも終了する。
|
ERR ter_tsk(W tskid)
W tskid 対象タスク ID
=0 正常 <0 エラー(エラーコード)
指定タスクを強制終了する。
指定できるタスクは、自プロセス内のサブタスクのみである。 自タスクおよびメインタスクを指定することはできない。
ER_ID : タスクID(tskid)が不正である。
|
ERR slp_tsk(W time)
W time タイムアウト時間 > 0 指定時間 ( ミリ秒 ) 待つ = -1 無限に待つ
=0 正常 <0 エラー(エラーコード)
自タスクを起床待ち状態にする。
time
で指定したタイムアウト時間だけ経過するか、
他タスクからタスク起床された場合に待ち状態が解除される。
ER_NONE : タイムアウト時間が経過したが、起床されなかった。 ER_MINTR : メッセージハンドラが起動されたため、待ちが中断された。 ER_PAR : パラメータ(time)が不正である。
|
ERR wup_tsk(W tskid)
W tskid 対象タスク ID
=0 正常 <0 エラー(エラーコード)
tskid
で指定したタスクが起床待ち状態であった時に、その待ちを解除する。
指定したタスクが起床待ち状態でない場合は、起床要求はキューイングされる。
指定するタスクは自プロセス内のタスクでなくてはいけない。 他プロセスのタスクを起床することはできない。また、自タスクを指定することはできない。
ER_ID : タスクID(tskid)が不正である。 ER_LIMIT : 起床要求のキューイング数が制限を超えた。
|
WERR can_wup(W tskid)
W tskid 対象タスク ID > 0 任意のタスク = 0 自タスク
≧0 正常(起床要求がキューイングされていた数) <0 エラー(エラーコード)
tskid
で指定したタスクにキューイングされている起床要求をすべてキャンセルする。
指定できるタスクは、自プロセス内のタスクのみである。
ER_ID : タスクID(tskid)が不正である。
|
ERR dly_tsk(W time)
W time 遅延時間( ミリ秒≧ 0 )
=0 正常 <0 エラー(エラーコード)
自タスクを指定した時間だけ待ち状態にする。
time = 0
を指定した場合は、
実行を中断して再スケジュールを行うことを意味する。
つまり、タスクの状態を実行状態から、実行可能状態へ移行させることになる。
ER_MINTR : メッセージハンドラが起動されたため、待ちが中断された。 ER_PAR : パラメータ(time)が不正である。
|
W get_tid()
なし
自タスクのタスク ID を取り出す。
発生しない。