Windows system >> Windowsの知識 >  >> Linuxシステムチュートリアル >> Linuxチュートリアル >> LINUXデバイスドライバ - レース、ブロック、リエントラントコード

LINUXデバイスドライバ - レース、ブロック、リエントラントコード

  

1.競合について

2つのプロセスが同時にデータを書き込むためにデバイスを開く場合、プロセスAがデータを書き込むときに新しいことになります。高速のデバイスメモリを適用し、新しいdevをデバイスのdevデータリンクテーブルに追加します。これにより、ポインタは新しいデバイスメモリブロックを指し、プロセスBの書き込み操作も同じ操作になります。プロセスが同時にオープンされている場合、2つのプロセスは同じデバイスデータリンクリスト情報を持ち、同じデータが変更されます最初の操作プロセスによって作成されたデータは、競合状態である後続のプロセスによって上書きされます。

ただし、カーネル内で実行されているコードはプリエンプティブではないため、1つのプロセッサでは発生しません。つまり、プロセッサは一度に1つのコードしか処理できません。しかし、マルチプロセッサシステムが発生する可能性があります。

LINUXは競合解決策を提供します。

1)セマフォ相互排除のために使われるセマフォ

#include

それはとても単純です。回避する必要があるデータブロックにタグを定義する必要がありますプロセスが使用されると、フラグは0に設定され、シグナルはすでに占有されていて再利用できないことを示します。それが0であるなら、それはプロセスが占有していることを意味します、あなたは待たなければなりません。

scull0のデータ構造Scull_Devにセマフォタグがあります。

しかし、セマフォはカーネルによって処理されます。プロセスをセマフォにしたいのです。セマフォを使用する場合、プロセスは自分自身でループされるのではなく、カーネルに渡されるべきです。セマフォを確認して待ちます。

さて、それはカーネル管理に渡される必要があるので、セマフォは初期化されなければなりません。

sema_init(& scull_devices.sem、1); //;セマフォを1に初期化して登録し、使用可能であることを示します。

セマフォを取得する必要がある場合は、down_interruptable(& sem)を呼び出し、セマフォを解放し(up)、セマフォを待機しているプロセスを起動して起動します。

if(down_interruptable(& dev-> sem))return -ERESTARTSYS; //;失敗した場合は直接戻り、呼び出すことはできません(& sem)//;データ操作...

up(& dev-> sem);

セマフォの使用には注意が必要です。プロセスがセマフォを保持していてセマフォの解放時に失敗した場合に表示されます。そうした場合、他のプロセスはブロックされます。

また、セマフォはプロセスをスリープさせるため、セマフォを割り込み処理に適用することはできません。

2)Lock

ご覧のとおり、セマフォを使用して、一方のプロセスがセマフォを保持している場合、もう一方のプロセスはスリープ状態になります。割り込み処理をスリープ状態にすることが許可されていない場合や、パブリックデータが他のプロセスによって占有されているかどうかをテストするだけの場合など、多くの場合、プロセスはスリープを待つ必要はありません。スピンロックを使用してください。もちろん、スピンロックを使用するとプロセッサが占有されるため、スピンロックは比較的短時間の間データを保持するのに適しており、ロックが保持されているときにスリープ状態に入ることは絶対に不可能です。

#include

spinlock_t my_lock = SPIN_LOCK_UNLOCKED;またはspin_lock_init(& my_lock);ロックの宣言/作成

spin_lock(spinlock_t * my_lock);指定のロックを取得spin_lockが返されると、呼び出し元の関数はspin_unlock(spinlock_t * my_lock)が解放されるまでロックを保持し、ロックは解放されます。 Br>

2.1ブロッキングについて

デバイスに読み込むデータがない場合、それを解決するには2つの方法があります1つは、直接読み取りエラーが発生しないようにすることです。 2つ目は、読み込み操作をブロックすることです。プロセスはスリープ状態に入り、データがあるときに起動します。

ここでブロッキングIOについて議論して、スリープとウェイクアップを処理します。

スリープとは、プロセスがイベントを待つ必要があるときに、一時的に中断してCPUを解放し、イベントが到着した後にウェイクアップすることです。

スリープを処理する1つの方法は、プロセスを待機キューに追加することです。

1)まず、待機キューエントリを宣言して初期化する必要があります。

#include

wait_queue_head_t my_queue;

init_waitqueue_head(& my_queue);

静的グローバル待ち行列を待っている場合は、上記の2つの定義を使用できます。

DECLARE_WAIT_QUEUE_HEAD( My_queue); //静的宣言はコンパイル時に自動的に初期化されます。

2)初期化された待機キュー項目を使用します。

カーネルの待機キューに参加する必要がある場合はinterrupt30_and_on(& my_queue)を呼び出します。;またはsleep_on(& my_queue)

ウェイクアップが必要な場合は、wake_up_interruptible(& my_queue);またはwake_up(& my_queue)

3)interruptible_sleep_on()の不具合

a。結果として生じる競合:

interrupt_on_sleep(on()や他のsleep_on関数によって引き起こされる可能性のある競合を理解するためには、interruptible_sleep_on()の実装についてもっと知る必要があります。

待機キューは実際にはキューリストであり、リスト内のデータはwait_queue_t型です。簡略化された内部interrupt_sleep_on()は、おそらく次のようになります。

#include

wait_queue_t wait; //;待機キューを定義する

init_wait_queue_entry(& wait、current); //;初期化

current-> state = TASK_INTERRUPTILBE; //;スリープ状態に設定して入るSleep

add_wait_queue(& my_queue、& wait); //;この待機キューに定義した待機キューアイテムを追加します

schedule(); //;実際にはスリープ状態に入ります

remove_wait_queue(& my_queue、& wait); //;イベントが到着し、schedule()が戻る

競合は現在の状態 - > state = TASK_INTERRUPTIBLEおよびschedule()で発生します場合によっては、ドライバがスリープ状態に入る準備ができているとき、つまりcurrent-> stateが設定されているときに、データが到着しただけである可能性があります。このプロセスは、ウェイクアップに応答していないために眠っています。そのため、この競争が生まれています。このレースは非常になりやすいです。解決策は、interruptible_sleep_on()を使用せず、代わりにその内部実装を直接使用することです。

例:

#include

wait_queue_t wait; //;待機キューを定義します。

init_wait_queue_entry(& wait、current); //;初期化

add_wait_queue(& my_queue、& wait); //;定義した待機キューエントリをこの待機キューに追加します。

while(1){

current-> state = TASK_INTERRUPTILBE; //;スリープに設定し、スリープ状態にする

if(short_head!= short_tail)break; //;データが到着しているかどうかをテストする、あれば飛び出す

schedule(); //;実際にはスリープ状態になります

}

set_current_state(TASK_RUNNING);

remove_wait_queue(& my_queue、& wait); //;イベントが到着し、schedule()が戻る

実際には、これらの複雑なことをカーネルなしで行うことができますカーネルはマクロを定義します

wait_event_interruptible(wq、condition);またはwait_event(wq、条件)条件はテストの条件です

Copyright © Windowsの知識 All Rights Reserved