カーネルソースを読む ( 5 ) ~ セマフォ ~

August 06, 2017

セマフォとは

Linux カーネルにより、アプリケーションのクリティカルセッションを保護するための仕組みであり、排他制御を実現する。

セマフォの初期化

セマフォを利用するにはセマフォ変数を用意してあらかじめ初期化しておく必要がある。
セマフォ変数は semaphore 構造体として定義され、init_MUTEX() で初期化を行う。

void init_MUTEX(struct semaphore *sem);

セマフォの獲得

セマフォの獲得によりカウンタを 1 つ減らす操作 ( P 操作 ) -> down()

void down(struct semaphore *sem);

割り込み可能なセマフォ獲得 -> down_interruptible()

int down_interruptible(struct semaphore *sem);

セマフォの開放

セマフォの開放には up() を用いる。
セマフォを開放し、カウンタを 1 つ増やす ( V 操作 )

void up(struct semaphore *sem);

注意点

セマフォは割り込みコンテキストでは使用できない。
割り込みコンテキスト内でセマフォが用いられ、もしスリープした場合には、最優先で処理される割り込みコンテキストを起こす処理が他にないため、そのままストールする。
つまり「使用できない」ではなく「使用してはいけない」

セマフォが使われている例

以下の drivers/net/wireless/airo.c で用いられている。
ユーザープロセスがシグナル受信で停止させられるように、down_interruptible() が使われている。
シグナルを受信した場合は readBSSListRid() はエラーを返す。
クリティカルセッションが終了した場合は up() でセマフォ開放をしている。

drivers/net/wireless/airo.c
static int readBSSListRid(struct airo_info *ai, int first,
		      BSSListRid *list)
{
	Cmd cmd;
	Resp rsp;

	if (first == 1) {
		if (ai->flags & FLAG_RADIO_MASK) return -ENETDOWN;
		memset(&cmd, 0, sizeof(cmd));
		cmd.cmd=CMD_LISTBSS;
		if (down_interruptible(&ai->sem))
			return -ERESTARTSYS;
		ai->list_bss_task = current;
		issuecommand(ai, &cmd, &rsp);
		up(&ai->sem);
		/* Let the command take effect */
		schedule_timeout_uninterruptible(3 * HZ);
		ai->list_bss_task = NULL;
	}
	return PC4500_readrid(ai, first ? ai->bssListFirst : ai->bssListNext,
			    list, ai->bssListRidLen, 1);
}

 © 2023, Dealing with Ambiguity