編集:seq_file
カーネルからユーザー空間への大量のデータの書き込みが容易になることがわかりました。私が探しているのは反対です。ユーザー空間からの大量のデータ (複数ページ) の読み取りを容易にする API。
編集 2 : のポートを<stdio.h>
カーネル モジュールとして実装しています。これは、s と/proc
同様に (および後で他の仮想ファイル システムを)開き、FILE
と同様に入力と出力を処理できます<stdio.h>
。プロジェクトはここにあります。
カーネルが大量のデータを /proc に書き込む方法 (ユーザー空間のプログラムが取得するため) に関する多くの質問を見つけましたが、その逆については何も見つかりませんでした。詳しく説明しましょう:
この質問は基本的に、データが複数の buffer 間で壊れている可能性があることを考えると、入力がトークン化されるアルゴリズムに関するものです (たとえば、int
s またはint
と string の混合物など) 。
たとえば、次のデータがカーネル モジュールに送信されているとします。
12345678 81234567 78123456 67812345 5678 1234 45678123 3456 7812 23456781
この例では、Linux が /proc ハンドラーにフィードするページ サイズが (実際の 4KB に対して) 20 バイトであるとします。
/proc (カーネルモジュール内) からデータを読み取る関数は、データを次のように認識します。
call 1:
"12345678 81234567 78"
call 2:
"123456 67812345 5678"
call 3:
" 1234 45678123 3456 "
call 4:
"7812 23456781"
ご覧のとおり78
、最初の呼び出しで が読み取られた場合、次のフレームまでまだ処理されず78
、整数かフレーム間の 1 カットかを判断する必要があります。
ここで、カーネルがユーザーにデータを読み取るのではなく書き込みseq_file
たい場合にのみ使用するように見える sを見つけました(または、HOWTO がひどく書かれている可能性があります)。
私がやった事
これまでのところ、次の解決策があります (記憶から書いているため、いくつかのエラー チェックを見逃している可能性がありますが、ご容赦ください)。
初期化フェーズ (たとえばinit_module
):
initialize mutex1 to 1 and mutex2 to 0
create /proc entry
call data_processor
/proc リーダー:
1. down(mutex1) /* down_interruptible of course, but let's not get into details */
2. copy_from_user to an internal buffer
buffer_index = 0
data_length = whatever the size is
3. strip spaces from end of buffer (except if all left from buffer is 1 space)
if so, there_was_space_after = 1 else 0
4. up(mutex2)
スペースを取り除く理由は後で説明します
get_int
関数:
wait_for_next = 0
number_was_cut = 0
last_number = 0
do
{
1. down(mutex2)
2. if (number_was_cut && !isdigit(buffer[buffer_index]))
break /* turns out it wasn't really cut
as beginning of next buffer is ' ' */
number_was_cut = 0
wait_for_next = 0
3. while (buffer_index < data_length && !isdigit(buffer_index[buffer_index]))
++buffer_index; /* skip white space */
4. while (buffer_index < data_length && isdigit(buffer[buffer_index]))
last_number = last_number * 10 + buffer[buffer_index++] - '0';
5. if (buffer_index >= data_length && !there_was_space_after)
number_was_cut = 1
wait_for_next = 1
up(mutex1) /* let more data come in */
else
up(mutex2) /* let get_int continue */
break
} while (wait_for_next)
return last_number
data_processor
関数 (例):
int first_num = get_int()
int sencod_num = get_int()
for i = first_num to second_num
do_whatever(get_int())
説明:まず、 を参照してくださいdata_processor
。データの読み取り方法の複雑さに関与しないため、整数を取得して、それらを必要に応じて処理します。/proc リーダーを見てみましょう。基本的に、現在のすべてのデータが消費されるのに十分な回数data_processor
を呼び出すのを待機しget_int
(ステップ 1)、次のバッファーを内部メモリにコピーして、data_processor
続行できるようにします (ステップ 2)。次に、末尾のスペースを削除する必要があるためget_int
、少し簡略化できます (ステップ 3)。最後に、get_int
データの読み取りを開始できることを通知します (ステップ 4)。
このget_int
関数は、最初にデータが到着するのを待ち (ステップ 1)、(ここではステップ 2 を無視します) 不要な文字をスキップし (ステップ 3)、数値の読み取りを開始します (ステップ 4)。数字の読み取りの終わりには、2 つの可能性があります。バッファの最後に達した場合 (この場合、/proc リーダーがスペースを削除していなければ、数値はフレーム間でカットされる) または空白が満たされます。前者の場合、/proc リーダーにさらにデータを読み込み、別のサイクルを待って残りの数値を現在の数値に追加するように通知する必要があり、後者の場合、数値を返します (ステップ 5)。最後のフレームから継続している場合は、新しいフレームが数字で始まるかどうかを確認します。そうでない場合、前の数値は実際には整数であり、返される必要があります。それ以外の場合は、最後の番号に数字を追加し続ける必要があります (ステップ 2)。
問題
この方法の主な問題は、非常に複雑なことです。が追加されると、はるかに複雑になりget_string
ます。または、読み取り整数が 16 進数などになる可能性があります。基本的に、再発明する必要がありますsscanf
。このsscanf
単純な例では、ループのget_int
代わりに(または も使用できますが、16 進入力も可能な場合はよりトリッキーになります (16 進数が 0 と x0212ae4 の間でカットされていることを想像してください)。それでも、のステップ 4 を置き換えるだけで、残りのものはそのままにしておく必要があります。while
get_string
get_int
実際には、すべての特殊なケースを完成させるために、多くのバグと厳しいテストが必要でした。それが私にはエレガントに見えないもう一つの理由です。
質問
これを処理するためのより良い方法があれば知りたいです。共有メモリの使用がオプションになる可能性があることは承知していますが、このタスクのアルゴリズムを探しています (既に実用的なソリューションがあるため、好奇心からです)。すなわち:
- Linux カーネルに、データを取得できる通常の C のように処理
FILE
でき、データをページ自体に分割する方法が既に実装されていますか? - いいえの場合、私は物事を複雑にしすぎていて、明らかな単純な解決策を見逃していますか?
fscanf
同様の問題に直面していると思います。これはそれによってどのように処理されますか?
副次的な質問: ミューテックスで /proc リーダーをブロックしているのはひどいことですか? つまり、データの書き込みがブロックされる可能性がありますが、それが通常ユーザー空間またはカーネル空間で発生するかどうかはわかりません。