私は現在、LinuxカーネルとOS全般について学んでおり、IRQ、ドライバー、スケジューリング、その他の重要なOSの概念に関する多くの優れたリソース、およびキーボード関連のリソースを見つけましたが、まとめるのに苦労しています。 Linuxカーネルがキーボードのボタン押下を処理する方法の包括的な概要。私はこの段階ですべての詳細を理解しようとしているのではなく、概念をある程度包括的に結び付けようとしています。
私は次のシナリオを念頭に置いています。
VIM
(Process #1
)とLibreOffice
(Process #2
)と言います。VIM
の中にいて、a
-キーを押します。ただし、現在実行中のプロセスはProcess #2
です(次にVIM
がスケジュールされます)。これは私が今下がることを想像する方法です:
APIC
)に送信されます。 APIC
は、プロセッサのINT Pin
をトリガーします。Kernel Mode
に切り替わり、APIC
からIRQ-Number
を要求します。これは、Interrupt Descriptor Table Register
(IDTR
)へのオフセットとして使用されます。記述子が取得され、それが割り込みハンドラルーチンのアドレスを取得するために使用されます。私が理解しているように、この割り込みハンドラーは最初にキーボードドライバーによって登録されましたか?これは私の主な質問に私をもたらします:割り込みハンドラルーチンはどのメカニズムによって押されたキーを正しいプロセス(Process #1
)に伝達しますか?それは実際にそれを行うのでしょうか、それとも単に押されたキーをバッファ(char-device
で利用可能)に書き込むのでしょうか。これは一度に1つのプロセスに対して読み取り専用です(現在は「接続済み」)からProcess #1
)? Process #1
受信キーがいつなのかわかりません。割り込みハンドラとしてデータをすぐに処理しますかschedulesすぐに処理しますか、それとも次にスケジューラがスケジュールしたときにキーデータを処理しますか?
IRET
)を返すと、コンテキストは以前に実行されていたプロセス(Process #2
)に戻されます。これまでの理解は正しいですが、それに基づいて構築された複雑さのほとんどを見逃しています。カーネルでの処理はいくつかのレイヤーで行われ、キーを押すとレイヤー全体が「バブルアップ」します。
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
に渡します。
十分に複雑ですか?
押されたキーをバッファに書き込むだけですか(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
私はあなたにこれらのキーワードを残します...