スリープ ウェイクアップ メカニズム、ポーリング メカニズム、非同期通知、タイマー、タスクレット、ワーク キュー、mmap、入力サブシステムを学習したら、落ち着いてみましょう。
1. 睡眠のメカニズム
ケース: APP プログラムがキー値を読み取る - スリープ メカニズム (ブロッキングまたは非ブロッキング)
1. キュー ヘッドの作成を待機します。
static DECLARE_WAIT_QUEUE_HEAD(key_waitqueue);
2. 待機列
wait_event_interruptible(wq, condition);
wq キューを待機しています。条件が true の場合、待機していることを意味し、その後戻ります。
3. キューを起動する
wake_up_interruptible(wq);
4. ノンブロッキングの仕組み
上記の方法はブロッキング方式ですが、ノンブロッキングにしたい場合はファイルを開くときにO_NONBLOCKフラグを付けてください。
fd = open(argv[1], O_RDWR | O_NONBLOCK);
ドライバも変更する必要があり、読み込み時にファイルのフラグがO_NONBLOCKになっているかどうかを判断する
if (!key_status && (filp->f_flags & O_NONBLOCK))
return -EAGAIN;
wait_event_interruptible(key_waitqueue, key_status);
「!key_status」は、現時点で読み取るキー値がないことを示します。そのため、この時点でO_NONBLOCKフラグが設定されている場合、キューを待機してEAGAINに直接戻る必要はありません。
2. ポール機構(目覚まし時計)
ケース: APP プログラムがキー値を読み取ります - ポーリング メカニズム (非ブロッキングの場合は、直接 0 に設定できます)
ポーリングメカニズムプロセスの詳細
コードフローチャート
3、fasync 非同期通知
ケース: APP プログラムがキー値を読み取る - fasync 非同期通知 (推奨)
fasync 非同期通知のコード フロー:
- APP プログラムはファイルを開き、シグナル関数 ( SIGIOシグナル)を定義します。
- fcntl関数を使用して、ファイルのフラグを設定し、プロセス PID を記録し、FASYNC/O_ASYNCフラグを設定します (これにより、ドライバー層のfasync関数の呼び出しがトリガーされます)。
- ドライバー層はfasync関数を実装し、fasync_helper関数を使用してfasync_struct構造体を初期化します(ファイルのフラグ ビットを保存します)。
- button を押した後にkill_fasync(&button_fasync, SIGIO, POLL_IN)を呼び出すと、 button_fasync->fa_fileからpidが取得され、SIGIOシグナルが送信されます。
- アプリケーションはシグナルハンドラー関数を実行します
PS: fasync機能を無効にしたい場合は、FASYNC/O_ASYNCフラグをブロックしてください。
fcntl(key_fd, F_SETFL, flags & ~O_ASYNC);
キーコードセクション:
アプリケーションキーコード
/* F_SETOWN: 设置将接收SIGIO和SIGURG信号的进程id */
fcntl(key_fd, F_SETOWN, getpid());
/* F_GETFL: 取得fd的文件状态标志 */
flags = fcntl(key_fd, F_GETFL);
/* O_ASYNC: 当I/O可用的时候,允许SIGIO信号发送到进程组,
例如:当有数据可以读的时候 */
fcntl(key_fd, F_SETFL, flags | O_ASYNC); //启动驱动的fasync功能
ドライバー層のキーコード:
struct fasync_struct *button_fasync;
...
...
static int key_fasync (int fd, struct file *filp, int on)
{
int retval;
retval = fasync_helper(fd, filp, on, &button_fasync);
if (retval < 0)
return retval;
return 0;
}
static struct file_operations key_ops = {
......
.fasync = key_fasync,
};
...
...
static irqreturn_t key_irq_handler(int irq, void *dev)
{
......
kill_fasync(&button_fasync, SIGIO, POLL_IN);
}