特にユーザー空間から要求せずに、カーネルからユーザー空間関数に文字列を送信する必要があります。カーネルのイベントを介してユーザー空間で関数またはアプリケーションをトリガーするようなものです。これまでのところ、ユーザー空間の init で開始してからスリープし、netlink について読み続ける Ioctl を試しましたが、適切に機能する例を見つけることができませんでした。提案や例は非常に義務付けられています。
3 に答える
これが私のプロセスの仕組みです。改善のための提案にも興味があります。
- カーネルモジュールを起動する
ユーザー空間アプリケーションを開始します。これにより、カスタム コマンドがカーネル モジュールに送信され、カーネル モジュール シグナル用のユーザー空間 PID が登録されます。私の場合、これは /dev/mymodule への書き込みによるものでした。カーネル モジュールは PID を登録します。
... printk("registering a new process id to receive signals: %d\n", current->pid); signal_pid = current->pid; ...
また、ユーザー空間アプリケーションは、特定のタイプのシグナルのカーネルにハンドラーを登録します。
void local_sig_handler(int signum) { printf("received a signal from my module\n"); fflush(stdout); } ... signal(SIGIO, local_sig_handler);
カーネルモジュールがシグナルを生成
... struct siginfo info; struct task_struct *t; info.si_signo=SIGIO; info.si_int=1; info.si_code = SI_QUEUE; printk("<1>IRQ received: %d\n", irq); printk("<1>searching for task id: %d\n", signal_pid); t= pid_task(find_vpid(signal_pid),PIDTYPE_PID);//user_pid has been fetched successfully if(t == NULL){ printk("<1>no such pid, cannot send signal\n"); } else { printk("<1>found the task, sending signal\n"); send_sig_info(SIGIO, &info, t); }
カーネルは信号をアプリケーションのハンドラに中継します
いくつかのオプションがあります:
- 信号。ユーザー プロセスはシグナル ハンドラーを定義し、カーネルはイベントの受信時にユーザー プロセスにシグナルを送信します。これはうまく機能しますが、処理コードを非同期シグナル ハンドラーで実行する必要があります (これにより、正しいコードを記述するのが難しくなります)。欠点は、シグナル ハンドラを使用して送信できるデータの量が多少制限されることです。プロセスがシグナルの処理中にメッセージを失わないように、必ずキューに入れることができるシグナル (リアルタイムシグナルなど) を使用してください。
- システム コールまたはファイル アクセスのブロック。ユーザー プロセスは、システム コールを実行 (またはファイルの読み取り/書き込み) してスリープ状態にします。呼び出しのカーネル ドライバーは、イベントのキューを維持し、イベントが到着したとき、およびブロックされたウェイターが存在するときにイベントをデキューします (これにより、ユーザー プロセスがブロックされていないときにイベントが失われるのを回避できます)。
- を構成するシステム コールを作成します
sigevent
。カーネル側でsigqueue
、関連するイベントを発生させる を作成します。
過去に使用した例は、カーネル空間のハードウェア割り込みからユーザー空間にシグナルを送信することでした。
カーネルスペース
シグナルを送信する前に、siginfo と task_struct を準備する必要があります。
struct siginfo info;
struct task_struct *t;
info.si_signo = SIG_TEST;
info.si_code = SI_QUEUE;
info.si_int = 1234; // Any value you want to send
rcu_read_lock();
また、ユーザー空間アプリケーション PID でタスクを見つけます。書き込みまたは ioctl 操作を介して、ユーザー空間からカーネル空間に送信する必要があります。
t = pid_task(find_pid_ns(pid, &init_pid_ns), PIDTYPE_PID);
その後、信号を送信できます。
rcu_read_unlock();
send_sig_info(SIG_TEST, &info, t);
ここでは省略しましたが、すべての操作の結果を確認する必要があります。
前のコードは、シグナル構造を準備して送信します。アプリケーションの PID が必要であることに注意してください。私の場合、ユーザー空間からのアプリケーションは、ioctl ドライバー プロシージャを介して PID を送信します。
ユーザースペース
コールバック関数を定義して実装する必要があります。
void signalFunction(int n, siginfo_t *info, void *unused) {
.....
.....
}
主な手順:
struct sigaction sig;
sig.sa_sigaction = signalFunction; // Callback function
sig.sa_flags = SA_SIGINFO;
sigaction(SIG_TEST, &sig, NULL);
お役に立てば幸いです。