アプリケーション:ハードウェアステータスをアクティブに読み取る①クエリ
方式:非常にリソースを消費する②割り込み
方式:読み取り関数は常にスリープし、決して返さない
③poll:スリープ時間を指定します
ドライバーはアプリケーションをトリガーし、アプリケーションはそれを再度読み取ります
。④非同期通知信号デバイスの準備が整うと、デバイスはアプリケーションにアクセスをアクティブに通知します。このように、非ブロッキングIOを使用するアプリケーションは、デバイスがアクセス可能かどうかをポーリングする必要がなく、CPU消費を削減するという目的を達成します。ハードウェアの「割り込み」の概念と同様に、より正確な用語は「信号駆動型非同期IO」です。信号:ソフトウェアレベルでの割り込みメカニズムのシミュレーションです。
原則として、プロセスは信号(ソフトウェア層)<==>(ハードウェア層)を受信し、プロセッサは割り込みを受信します。
Killコマンド:Linuxのkillコマンドは、指定されたプロセスの操作を終了する(プロセスを終了する)ために使用され、Linuxでのプロセス管理の一般的なコマンドです。通常、Ctrl + Cキーを使用してフォアグラウンドプロセスを終了できますが、バックグラウンドプロセスの場合は、killコマンドを使用して終了する必要があります。プロセスを取得するには、ps / pidof / pstree / topなどのツールを使用する必要があります。 PIDを入力し、killコマンドを使用してプロセスを強制終了します。killコマンドは、指定されたシグナルをプロセスに送信することにより、対応するプロセスを終了します。デフォルトでは、TERM信号番号15が使用されます。TERMシグナルは、シグナルをキャッチできないすべてのプロセスを終了します。シグナルをキャプチャできるプロセスの場合、killシグナル番号9を使用して、プロセスを強制的に「kill」します。
kill -USER1(シグナル)PID(指定されたプロセス番号)
例:
1。プロセス番号を表示します
2. kill -USER1 833
- 目標:ボタンが押されると、ドライバーはアプリケーションに通知します
- 信号処理機能を登録しますか?応用
- 誰が合図したのですか?ドライバーシグナリング
- 誰に?アプリケーション、アプリケーションはドライバーにそのPID番号を伝える必要があります
- 送信方法は?ドライバーは
kill_fasyn
関数を呼び出して送信します
以下の実装コードを見てください
デバイスが非同期通知メカニズムをサポートするようにするために、次の3つのタスクがドライバーに含まれます。
- F_SETOWNコマンドをサポートし、この制御コマンド処理で対応するプロセスIDとしてfilp-> f_ownerを設定できます。ただし、この作業はカーネルによって完了されており、デバイスドライバーを処理する必要はありません。
- F_SETFLコマンドの処理をサポートします。FASYNCフラグが変更されると、ドライバーのfasync()関数が
実行されます。fasync()関数はドライバーに実装する必要があります。 - デバイスリソースが利用可能な場合は、kill_fasync()関数を呼び出して、対応するシグナルをトリガーします
ドライバー
- 構造を定義します。
static struct fasync_struct *button_async;
- 割り込み処理機能:
static irqreturn_t buttons_irq(int irq, void *dev_id)
{
...
kill_fasync (&button_async, SIGIO, POLL_IN);//发送的信号类型:SIGIO
...
}
誰がbutton_async
構造を初期化しますか?
fifth_drv_fasync
関数の初期化button_async
構造
static struct file_operations sencod_drv_fops = {
.owner = THIS_MODULE,
.open = fifth_drv_open,
.read = fifth_drv_read,
.release = fifth_drv_close,
.poll = fifth_drv_poll,
.fasync = fifth_drv_fasync, //
};
static int fifth_drv_fasync (int fd, struct file *filp, int on)
{
printk("driver: fifth_drv_fasync\n");
return fasync_helper (fd, filp, on, &button_async);//这里初始化button_async结构体
}
fifth_drv_fasync
関数はいつ呼び出されますか?アプリプログラムがドライバーを呼び出す.fasync
ときに呼び出されます。
//把自己的进程号pid告诉驱动程序;
//支持 F_SETOWN 命令,能在这个控制命令处理中设置 filp->f_owner 为对应进程 ID。不过此项工作已由内核完成,设备驱动无须处理。
app > fcntl(fd,F_SETOWN,pid)
//读出F_GETFL
//支持 F_SETFL 命令的处理,每当 FASYNC 标志改变时,驱动程序中的 fasync()函数将得以执行。驱动中应该实现 fasync()函数。
app > Oflags = fcntl(fd,F_GETFL)
app > fcnl(fd,F_SETFL,oflags | FASYNC)
2番目のアプリケーション
- 信号応答関数と応答信号タイプを宣言します
//信号响应函数:my_signal_fun
//相应信号类型:SIGIO
signal(SIGIO, my_signal_fun);
- 信号応答関数の定義
//从fd中读取按键值到key_val
void my_signal_fun(int signum)
{
unsigned char key_val;
read(fd, &key_val, 1);
printf("key_val: 0x%x\n", key_val);
}
ドライバーの割り込みサービス機能が信号を検出すると、その信号をアプリプログラムに直接送信し、アプリプログラムは信号処理機能にジャンプしますmy_signal_fun
。
//发给谁?
//把自己的进程号pid告诉驱动程序;
//getpid()函数表示获取的进程号
fcntl(fd, F_SETOWN, getpid());
//改变FASYNC标记,最终会调用到驱动的fasync > fasync_helper:初始化/释放fasync_struct
//驱动程序中的 fasync()函数将得以执行
Oflags = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, Oflags | FASYNC);//设置文件描述符标志
fasync_helper関数の3つの簡単な分析
呼び出し:fasync_helper (fd, filp, on, &button_async)
関数:構造button_async
初期化
関数のプロトタイプを宣言します。
int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fapp)
int fd= fd;
struct file * filp = filp;
int on = on;
struct fasync_struct **fapp = &button_async
関数定義:
int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fapp)
{
...
//1. 参数on控制,如果为on分配一个结构体new
if (on) {
new = kmem_cache_alloc(fasync_cache, GFP_KERNEL);
if (!new)
return -ENOMEM;
}
write_lock_irq(&fasync_lock);
for (fp = fapp; (fa = *fp) != NULL; fp = &fa->fa_next) {
if (fa->fa_file == filp) {
if(on) {
fa->fa_fd = fd;
kmem_cache_free(fasync_cache, new);
} else {
*fp = fa->fa_next;
kmem_cache_free(fasync_cache, fa);
result = 1;
}
goto out;
}
}
//与1.对应,刚刚分配的结构体new进行初始化后,赋给fapp即&button_async
if (on) {
new->magic = FASYNC_MAGIC;
new->fa_file = filp;
new->fa_fd = fd;
new->fa_next = *fapp;
*fapp = new;
result = 1;
}
out:
write_unlock_irq(&fasync_lock);
return result;
}