[kernel-ml 31] Re: TASK&STACK

Naitoh Ryuichi ((no email))
Tue, 6 Jun 1995 22:11:28 +0900

隆一です。

まず報告から。
以前、このメイリングリストで MS-DOS のファイルシステムを読むプログラム
を作っているということを書きました。今までそのプログラムを boot プログ
ラムに組み込もうとしていたのですが、昨日、なんとか FD のトップディレク
トリの一覧を出せるようになりました。
よぉっし、あともう少しだ!

----------------------------------------------------------------------
以下ではここ 2、3 日議論し続けているプロセス内タスクでスタックを共有で
きるようにするか、ということについてコメントします。

>> On Tue, 06 Jun 1995 17:46:00 +0900, 藤永清和 <NBA01614@niftyserve.or.jp> said:

>  kernel-mlのみなさん、藤永です。
> 隆一さん[kernel-ml 29]より>
> 注意しなければいけないのは、C 言語では、局所変数は必ずしもひとつの関数
> の中でのみ見ることのできるデータを意味していないということです。
> 局所変数のアドレスを大域変数(ポインタ)に入れたり、引数で渡すことによっ
> て、その関数以外でも見ることができるようになります。
> <<<
>  そのとおりです。しかし、局所変数は、呼び出された関数では保証されますが、変
> 数を定義した関数が終了したら消えて亡くなるものでしょう。だから、局所変数(自
> 動変数)を引数で引き渡すことはあっても、大域変数に入れて別の関数に参照させる
> ようなコーディングをしたことがありません。

>  たとえば、隆一さんが[kernel-ml 21]で示されたプログラムで、task1が、終了し
> たあとでは、task2は、あらぬデータをアクセスします。

えーと、ちょっと議論が違った方向に行ってしまったような。。

今まで私の行っていた問題は、大域変数を介してスタック上の値を共有させる
場合だけでなく、引数で渡した場合にもおこります。
スタック上の領域を引数で渡す場合を考えてみます。
この例では、simple_printf () は、2つの出力先 --- コンソールとログ領域
に引数の文字列を出力します。

parent ()
{
char message[14] = "Hello world!\n";

simple_printf (message);
}

simple_printf (char *message)
{
print_console (message);
log (message);
wait_task (); /* print_console() と log() の処理が終わ */
/* るのを待つ */
}

ここで、print_console () が処理の延長でタスクを生成しているします。
そうすると、子のタスクからは message が入っているスタックはアクセスで
きず自分のもっているスタックから取ってきたでたらめな値が出力されること
になります。

# え? メッセージボックスを使って文字列を送ればいいって?
# たしかに、そうです :-) が、同じ仮想空間を共有しているタスクでそれは
# ないでしょう。仮想空間を共有してデータのやりとりをすばやく行うように
# できるのがプロセス内タスクの機構の利点のはずですから。

>  局所変数を大域変数に入れて他の関数やタスクに渡すのは非常に危険なだけで利点
> があるとは思えないのですが?

上に示したように、私が言いたいのはスタック上の領域を複数のタスクで共有
する場合があるということを言いたかっただけです(元の例がわるかったかな?)
大域変数を介するというのは、他のタスクからデータをアクセスすることを簡
単に示せる例として出しただけです。

>  隆一さんの趣旨は、「スタック上の局所変数なのか、それとも大域変数なのか判別
> すること」が困難だから、
> *というわけで、私は「タスク間でスタックの中身を共有できない」という仕様
> *には反対です。
> なのですね。
>  しかし、スタックの共有を許したところで、スタック上の変数が保証できるわけで
> はありません。

しかし、「子タスクが終了するまで親タスクは待つ」という、それほど無理の
ない制限でスタック上の変数があることを保証できるようになると思います。

タスク間でスタックの情報を共有できないということは、子タスクへのデータ
を渡すのは大域変数のみということになります。子タスクを関数のように呼び
出すという使いかたをした場合、大域変数をアクセスするのは引数より繁雑の
ような気がします(他のタスクが大域変数をアクセスする場合があるから排他
処理が必要ですが、スタック上の値ならば排他処理は省くことができる場合が
あります)。

関数呼び出しのように動的にタスクを生成する場合を考えてみると、新しく作っ
たタスクにスタック上の引数をそのまま渡すというのは、特におかしい使い方で
はないと思います。どうでしょうか?

>  プロセス間でも、スタックに積まれたデータを共有メモリを介して参照するコード
> を書くことは可能です。しかし、それは認めませんでしょう?

この場合には、むしろスタックを共有できないようにしたケースのことを言っ
ているのだと思いますが。。。
(スタックは共有領域ではないから)

# こういうケースというのは、単にバグだと思います :-)。<- ちゃちゃ

>  「タスク間でスタックの中身を共有する」ことを保証する方法が思い付きません。

簡単に言えば、「あるタスクが子供のタスクを生成した場合、子供のタスクの
処理が終わるまで処理を中断する」というのが基本になると思います。

つまり、

(1) 親タスクが子タスクを(複数)生成する。
(2) それぞれの子タスクが仕事をする。
(3) 親タスクが子タスクの終了を待つ。

という感じのコードになると思います。

>  まだ、私の勘違いや誤解が有るかもしれません。で、この件については次回ミーテ
> ィングのときに議論して、結論はしばらく待っていただきたいと思います。

はい、そうしましょう。

>  いまのところは、「プロセスは、一つ以上(一つまたは複数)のタスクを持てる。
> 」ことを実現するためには、TCBやPCB(プロセス管理情報)にどんなデータが
> 必要か考えておきたいです。(プロセス内マルチタスクは電祭までに実現しなくても
> よいと思いますが)

プロセスというオブジェクトを中心核で関知しないものとすれば、TCB は変更
の必要がないと思います。B-Free OS では、BTRON の他に POSIX のインタフェー
スも動くようにする予定ですが、BTRON プロセスと POSIX プロセスは同じ動
きをするわけではありません。
中心核からみると同じプロセスに属するタスクは、仮想空間を共有しているタ
スクに見えるだけです。

私も、プロセス内タスクについては、特に急いで実現する必要はないと思いま
す。

-- 
内藤隆一 (ggc00661@niftyserve.or.jp/night@bfree.rim.or.jp)