セマフォメカニズムの上下機能



Down Up Functions Semaphore Mechanism



からの転送: https://blog.csdn.net/fzubbsc/article/details/37737159

参照:



https://blog.csdn.net/liuxd3000/article/details/17913363

http://blog.chinaunix.net/uid-25845340-id-3017214.html



https://blog.csdn.net/xiao229404041/article/details/7031776

ファイルを確認してください:

kernel linux linux-4.4.3 kernel locking semaphore.c



kernel linux linux-4.4.3 include linux semaphore.h

DOWN操作:Linuxカーネルでは、セマフォのDOWN操作は次のとおりです。

1、void ダウン (struct semaphore * sem)//中断不能

ダウンインターフェイスは、セマフォを要求するために使用されます。この関数を呼び出すと、シグナルが取得されるまで呼び出し元のスレッドがスリープ状態になります。同時に、この関数の呼び出しは割り込みを許可しません。
この関数では、最初にセマフォリソースの数を確認します。セマフォデータ(カウント)が0でない場合は、1ずつデクリメントして戻ります。それ以外の場合は、呼び出しは成功します。それ以外の場合は、__ downが呼び出されます。待っていると、発信者はスリープします。

2、int down_interruptible (struct semaphore * sem)//割り込み可能

機能はダウンに似ています。違いは、ダウンがシグナルによって中断されないことですが、down_interruptibleはシグナルによって中断される可能性があるため、関数には、正常かシグナルが中断されたかを区別するための戻り値があります。 、セマフォが正常に返されることを示し、信号によって中断された場合は-EINTRを返します。

3、int down_killable (struct semaphore * sem)//スリーププロセスは致命的な信号によって目覚め、セマフォを取得する操作を中断する可能性があります。

Down_killableはdown_interruptibleに似ており、着信__down_commonの実際の引数が異なるため(TASK_KILLABLEとTASK_INTERRUPTIBLE)、ここではそれ以上の分析は実行されません。

4、int down_trylock (struct semaphore * sem)/ /セマフォを取得しようとします。使用できない場合は、スリープせずに直接1を返します。 0を返すことは、セマフォが取得されたことを意味します。

down_trylockインターフェースはセマフォを取得しようとするために使用されますが、このインターフェースは発信者をスリープさせません。使用可能なセマフォがない場合は、すぐに戻ります。 0を返すと、セマフォは成功します。 1を返すと、取得は失敗します。したがって、このインターフェイスを呼び出すときは、戻り値をチェックして、成功するかどうかを確認する必要があります。

5、int down_timeout (struct semaphore * sem、long jiffies)/ /スリープ時間が制限されていることを示します。jiffiesで指定された時間が経過してもセマフォが使用できない場合は、エラーコードが返されます。

down_timeoutインターフェイスの実装プロセスは、downインターフェイスの実装と似ていますが、インターフェイスがタイムアウト期間をカスタマイズできる点が異なります。つまり、時間外にセマフォを取得できない場合、呼び出し元は次の理由で自動的にウェイクアップします。タイムアウト。実装プロセスは次のとおりです。着信タイムアウトパラメータに注意してください。 TASK_UNINTERRUPTIBLEの場所

上記の5つの関数の中で、最も頻繁に使用されるドライバーはdown_interruptible関数であり、以下で分析します。

down_interruptible関数の定義は次のとおりです。

機能分析: この関数は、spin_lock_irqsaveを呼び出すことにより、最初にsem-> count操作のアトミック性を保証します。 count> 0の場合、現在のプロセスがセマフォを取得し、countの値をデクリメントして、終了できることを意味します。 countが0以下の場合、現在のプロセスがセマフォを取得できないことを示し、__ down_interruptibleが呼び出され、後者は引き続き__down_commonを呼び出します。

__down_common関数は次のように定義されています。

static inline int __sched __down_common(struct semaphore *sem, longstate, longtimeout) { struct task_struct *task= current struct semaphore_waiterwaiter list_add_tail(&waiter.list,&sem->wait_list) waiter.task = task waiter.up = 0 for () { if(signal_pending_state(state, task)) gotointerrupted if (timeout lock) timeout =schedule_timeout(timeout) spin_lock_irq(&sem->lock) if (waiter.up) return 0 } timed_out: list_del(&waiter.list) return -ETIME interrupted: list_del(&waiter.list) return -EINTR }

機能分析: 以下の操作は、__ down_common関数の数に対して実行されました。

(1)現在のプロセスをセマフォメンバー変数wait_listによって管理されるキューに入れます。

(2)forループでは、現在のプロセス状態はTASK_INTERRUPTIBLEです。現在のプロセスをスリープ状態にするためにschedule_timeoutが呼び出されると、関数はschedule_timeout呼び出しに留まり、再度実行されるようにスケジュールされていることを認識します。

(3)プロセスが再度スケジュールされると、次の理由に従って対応する操作が実行されます。waiter.upが0でない場合、プロセスはセマフォのアップ操作によって起動され、プロセスはセマフォを取得できます。プロセスが、ユーザースペースによって中断されたシグナルまたはタイムアウトシグナルによって引き起こされたウェイクアップである場合、対応するエラーコードが返されます。

UP操作:LINUXカーネルはup機能のみを提供します

up関数は次のように定義されます。

void up(struct semaphore *sem) { unsigned long flags spin_lock_irqsave(&sem->lock,flags) if(likely(list_empty(&sem->wait_list))) sem->count++ else __up(sem) spin_unlock_irqrestore(&sem->lock,flags) }

機能分析: semのwait_listキューが空の場合、他のプロセスがセマフォを待機していないことを意味し、semカウントに1を追加するだけで済みます。 wait_listキューが空でない場合は、他のプロセスがwait_listのシグナルを待ってスリープしていることを意味します。このとき、プロセスをウェイクアップするために__up(sem)が呼び出されます。

__up()関数は次のように定義されています。

static noinline void __sched __up(struct semaphore *sem) { struct semaphore_waiter*waiter = list_first_entry(&sem->wait_list, structsemaphore_waiter, list) list_del(&waiter->list) waiter->up = 1 wake_up_process(waiter->task) }

機能分析: 関数では、wake_up_processが呼び出されてプロセスがウェイクアップされるため、プロセスは前の__down_interruptible呼び出しのtimeout = schedule_timeout(timeout)からウェイクアップし、wait-up = 1、__ down_interruptibleは0を返し、プロセスはセマフォを取得します。

up()関数とdown()関数の関係: 上記の2つの関数の分析から、__ down_common関数のtimeout = schedule_timeout(timeout)が重要な役割を果たしていることがわかります。

注:プロセスがdown_interruptible()を呼び出した後、semの場合<0, then it enters an interruptible sleep state and schedules other processes to run, but once the process receives a signal, it returns from the down_interruptible function. And mark the error number as: -EINTR. The analogy of an image: the incoming semaphore is 1 is better than dawn. If the current semaphore is 0, the process sleeps until (the semaphore is 1). It wakes up, but there may be an alarm (signal) that wakes you up. . Another example: Xiaoqiang’s school after school in the afternoon, when he returns home, he will start eating. There will be two situations at this time: Situation 1: When the meal is ready, you can start eating Case 2: When he goes to the kitchen, he finds My mother is still doing it, and my mother said to him: 'You go to sleep first, and you will be ready to call you later.' Xiaoqiang promised to go to sleep, but said: 'The time to sleep is Xiaohong. Look for me to play, you can wake me up.' Xiaoqiang is down_interruptible, want to eat is to get the semaphore, sleep corresponds to the sleep here, and Xiaohong came to me to play is interrupted sleep.

割り込み可能なセマフォバージョンの使用は、セマフォでデッドロックが発生した場合に、ctrl + cでソフト割り込みを発行して、カーネルドライバーが戻るのを待っているユーザーを許可する機会があることを意味します。状態プロセスは終了します。システム全体をロックする代わりに。スリープ中は、割り込み信号で終了できます。このプロセスは割り込み信号を受け入れることができます!たとえば、コマンドラインで#sleep 10000と入力し、ctrl + cを押すと、プロセス終了信号が上記のプロセスに送信されます。信号はユーザースペースに送信され、システムコールを介してドライバーに渡されます。シグナルはユーザースペースにのみ送信でき、カーネルに直接送信する権利はありません。 1Gカーネルスペースを直接操作することはできません。 ---------------------この記事はlixd3000のCSDNブログ、フルテキストアドレスからのものです。https://blog.csdn.net/liuxd3000/articleをクリックしてください。 / details / 17913363?utm_source = copy