web-dev-qa-db-ja.com

Linuxカーネルでキーボードプレスはどのように処理されますか?

私は現在、LinuxカーネルとOS全般について学んでおり、IRQ、ドライバー、スケジューリング、その他の重要なOSの概念に関する多くの優れたリソース、およびキーボード関連のリソースを見つけましたが、まとめるのに苦労しています。 Linuxカーネルがキーボードのボタン押下を処理する方法の包括的な概要。私はこの段階ですべての詳細を理解しようとしているのではなく、概念をある程度包括的に結び付けようとしています。

私は次のシナリオを念頭に置いています。

  1. 私はシングルプロセッサを搭載したx64マシンを使用しています。
  2. 実行中のプロセスがいくつかあります。特に、エディターVIMProcess #1)とLibreOfficeProcess #2)と言います。
  3. 私はVIMの中にいて、a-キーを押します。ただし、現在実行中のプロセスはProcess #2です(次にVIMがスケジュールされます)。

これは私が今下がることを想像する方法です:

  1. キーボードは、一連の手順を実行して、USBワイヤに送信する電気信号(USBプロトコルエンコーディング)を生成します。
  2. 信号はUSBコントローラーによって処理され、PCI-e(および場合によっては他のコントローラー/バス?)を介して割り込みコントローラー(APIC)に送信されます。 APICは、プロセッサのINT Pinをトリガーします。
  3. プロセッサはKernel Modeに切り替わり、APICからIRQ-Numberを要求します。これは、Interrupt Descriptor Table RegisterIDTR)へのオフセットとして使用されます。記述子が取得され、それが割り込みハンドラルーチンのアドレスを取得するために使用されます。私が理解しているように、この割り込みハンドラーは最初にキーボードドライバーによって登録されましたか?
  4. 割り込みハンドラルーチン(この場合はキーボードハンドラルーチン)が呼び出されます。

これは私の主な質問に私をもたらします:割り込みハンドラルーチンはどのメカニズムによって押されたキーを正しいプロセス(Process #1)に伝達しますか?それは実際にそれを行うのでしょうか、それとも単に押されたキーをバッファ(char-deviceで利用可能)に書き込むのでしょうか。これは一度に1つのプロセスに対して読み取り専用です(現在は「接続済み」)からProcess #1)? Process #1受信キーがいつなのかわかりません。割り込みハンドラとしてデータをすぐに処理しますかschedulesすぐに処理しますか、それとも次にスケジューラがスケジュールしたときにキーデータを処理しますか?

  1. このハンドラーが(IRET)を返すと、コンテキストは以前に実行されていたプロセス(Process #2)に戻されます。
1
Sean

これまでの理解は正しいですが、それに基づいて構築された複雑さのほとんどを見逃しています。カーネルでの処理はいくつかのレイヤーで行われ、キーを押すとレイヤー全体が「バブルアップ」します。

USB通信プロトコル自体はもっと複雑です。 USBの割り込みハンドラルーチンはこれを処理し、必要に応じて複数のフラグメントから完全なUSBパケットをアセンブルします。

キーを押すと、USB上に構築されたいわゆる [〜#〜] hidden [〜#〜] ( "ヒューマンインターフェイスデバイス")プロトコルが使用されます。したがって、下位のUSBカーネル層は、メッセージ全体がUSB HIDイベントであることを検出し、それをカーネルのHID層に渡します。

HIDレイヤーは、初期化時にデバイスから要求されたHID記述子に従ってこのイベントを解釈します。次に、イベントを入力レイヤーに渡します。 1つのHIDイベントで、複数のキー押下イベントを生成できます。

入力レイヤーは、カーネルキーボードレイアウトテーブルを使用して、スキャンコード(キーボード上のキーの位置)をキーコード(Aなど)にマップし、解釈します。 Shift、 Alt、など。この解釈の結果は、/dev/input/event*を介してユーザーランドプロセスに提供されます。 evtestを使用して、これらのイベントをリアルタイムで監視できます。

しかし、ここでは処理は終了していません。 Xサーバー(グラフィックスを担当)には、/dev/input/event*デバイスからイベントを読み取り、それらを再度マップする汎用のevdevドライバーがありますキーボードレイアウトテーブルの2番目のセットによると(一部はxmodmapで、完全にはXKBD拡張を介して表示できます)。これは、Xサーバーがカーネル入力レイヤーよりも前のものであり、以前はマウスキーとPS/2キーを直接処理するドライバーがあったためです。

次に、Xサーバーはキーボードイベントを含むメッセージをXクライアント(アプリケーション)に送信します。これらのメッセージは、xevアプリケーションで確認できます。 LibreOfficeはこのイベントを直接処理し、VIMはイベントを処理するxtermで実行され、(ご想像のとおり)再び処理を追加します。最後に、それをVIM経由でstdinに渡します。

十分に複雑ですか?

4
dirkt

押されたキーをバッファに書き込むだけですか(charデバイスから利用できますか?)

はい、言うべきです。

そして、(低レベル)コンソールからtty(仮想)そして疑似ttyへの一種のカスケードがあります。キーを押すと、アクティブな「コンソール」に応じて/ dev/tty1または/ dev/tty5に書き込まれます。

そしてxterm(ps axf出力)では:

  467 tty1     Ss     0:38  \_ -bash
 5820 tty1     S+     0:00      \_ xinit fvwm -- vt9
 5821 tty9     S<sl+  54:15          \_ /usr/lib/Xorg :0 vt9
 5831 tty1     S      0:00          \_ xterm -geometry +1+1 -n login fvwm
 5833 pts/0    Ss+    0:38              \_ fvwm
 ...
 ...
  773 pts/0    S      0:07                  \_ xterm
  775 pts/2    Ss+    0:00                  |   \_ bash
14452 pts/0    S      0:04                  \_ xterm
14454 pts/1    Ss     0:00                  |   \_ bash
14507 pts/1    S      0:00                  |       \_ xfontsel
31044 pts/1    R+     0:00                  |       \_ ps ax f
19549 pts/0    S      0:00                  \_ xterm
19551 pts/3    Ss+    0:00                      \_ bash

これは、Xorgがtty1からtty9でどのように開始されるか、およびfvwm(ウィンドウマネージャー)とxterm(ターミナルエミュレーター)が/ dev/pts/0を「取得」する方法を示し、/ dev/pts/1、ptsを取得するのは新しいシェルです。/2。 pts/3など。

これで、そのpid 19551 pts/3 bashプロセスをpointingでxtermウィンドウでアクティブにしてからキーを押すか、または/のようなコンソールvtからecho hello >/dev/pts/3を実行するかどうかは関係ありません。 dev/tty5、文字は正しいプロセスに進みます。

man psは、プロセス状態コードの下で説明します(まあ、それはそれらをリストします):

S    interruptible sleep (waiting for an event to complete)
s    is a session leader    
+    is in the foreground process group

私はあなたにこれらのキーワードを残します...

0
rastafile