web-dev-qa-db-ja.com

Linuxドライバーの作成中にERESTARTSYSは何を使用しましたか?

Linuxデバイスドライバーを作成するためのブロッキングI/O関数について学び、ERESTARTSYSの使用方法を知りたいです。以下を検討してください。

グローバル変数:

_wait_queue_head_t my_wait_q_head;
int read_avail = 0;
_


device_init():

init_waitqueue_head(&my_wait_q_head);


device_read():

_printk("I'm inside driver read!\n");
wait_event_interruptible(&my_wait_q_head, read_avail != 0);
printk("I'm awaken!\n");
_


device_write():

_read_avail = 1;
wake_up_interruptible(&my_wait_q_head);
_


ユーザースペースからread()を呼び出すと、期待どおりにwrite()を呼び出すまでコマンドプロンプトがハングします。 printkメッセージもdmesgに表示されます。ただし、次のように書かれたドライバがいくつかあります。

Device_read()の別のバージョン:

_printk("I'm inside driver read!\n");
if(wait_event_interruptible(&my_wait_q_head, read_avail != 0))    
{return -ERESTARTSYS;}
printk("I'm awaken!\n");
_

ユーザー空間で同じメソッドを使用してdevice_read()の2番目のバージョンをテストしました。結果はまったく同じなので、ERESTARTSYSの用途は何ですか?

p/s:これについては、Linux Device Driverという本を読んだのですが、理解できません。誰かが例を挙げて詳しく説明できますか?:

その呼び出しを通過すると、何かが起きてしまいましたが、何が起きているのかわかりません。 1つの可能性は、プロセスがシグナルを受信したことです。 wait_event_interruptible呼び出しを含むifステートメントは、このケースをチェックします。このステートメントは、シグナルへの適切で予期される反応を保証します。これは、プロセスをウェイクアップする原因となった可能性があります(割り込み可能なスリープ状態だったため)。シグナルが到着し、プロセスによってブロックされていない場合、適切な動作は、カーネルの上位層にイベントを処理させることです。このために、ドライバーは呼び出し元に-ERESTARTSYSを返します。この値は、仮想ファイルシステム(VFS)レイヤーによって内部的に使用され、システムコールを再起動するか、ユーザー空間に-EINTRを返します。同じタイプのチェックを使用して、すべての読み取りおよび書き込み実装の信号処理を処理します。

ソース: http://www.makelinux.net/ldd3/chp-6-sect-2

29

-ERESTARTSYSは、再起動可能なシステムコールの概念に関連しています。再起動可能なシステムコールは、割り込みが発生したときにカーネルによって透過的に再実行できるシステムコールです。

たとえば、システムコールでスリープしているユーザー空間プロセスは、シグナルを受け取ってハンドラーを実行し、ハンドラーが戻ると、カーネルに戻って元のシステムコールでスリープし続けるように見えます。

POSIXの使用 sigaction APIのSA_RESTARTフラグ。プロセスは、シグナルに関連付けられた再起動動作を調整できます。

Linuxカーネルでは、システムコールのコンテキストでブロックしているドライバーまたは他のモジュールが、タスクがシグナルのために起こされたことを検出すると、-EINTRを返すことがあります。ただし、-EINTRはユーザー空間にバブリングし、システムコールはerrnoをEINTRに設定して-1を返します。

代わりに-ERESTARTSYSを返す場合は、システムコールが再起動可能であることを意味します。 ERESTARTSYSコードは、必ずしもユーザー空間に表示されるとは限りません。これは、-1の戻りに変換され、errnoがEINTRに設定されます(その後、明らかにユーザー空間で表示されます)、またはシステムコールの再起動動作に変換されます。つまり、同じ引数を使用してsyscallが再度呼び出されます(ユーザー空間プロセスの一部に対してアクションはありません。カーネルは、特別な再起動ブロックに情報を隠しておくことでこれを行います。

前の段落の「同じ引数」の明らかな問題に注意してください。一部のシステムコールは、べき等ではないため、同じパラメーターで再起動できません。たとえば、5.3秒間、nanosleepのようなスリープコールがあるとします。 5秒後に中断されます。単純に再起動すると、さらに5.3秒間スリープします。残りの0.3秒間だけスリープするには、再起動された呼び出しに新しいパラメーターを渡す必要があります。つまり、再起動ブロックの内容を変更します。これを行う方法があります。タスクの再起動ブロックにさまざまな引数を入れ、-ERESTART_RESTARTBLOCK戻り値を使用します。

2番目の質問に対処するには:違いは何ですか?戻り値をチェックして-ERESTARTSYSを返さずに、単に読み取りルーチンを作成しないのはなぜですか?まあ、それはウェイクアップが信号による場合は正しくないからです!シグナルが到着するたびに、読み取りで0バイトの読み取りを返しますか?これは、データの終わりとしてユーザー空間によって誤って解釈される可能性があります。この種の問題は、信号を使用しないテストケースでは発生しません。

49
Kaz