Windows system >> Windowsの知識 >  >> Linuxシステムチュートリアル >> LinuxシステムFAQ >> Linux procファイルの読み取りseq

Linux procファイルの読み取りseq

  

Linuxでは、procファイルシステムを介してユーザー状態とカーネル状態の相互作用またはカーネルの微調整を行うことは比較的簡単で効果的な方法です。最近、プロジェクトのニーズにより、procを通してカーネルモジュールのデータをユーザーモードに出力し、seq_fileを学ぶ機会を得る必要があります。ここで簡単な記録を作りなさい、そして間違った場所は批判を歓迎する。 seq_fileを使用するには、#include

が必要です。さて、ナンセンスな話はしないで、始めましょう、^ _ ^。私たちのカーネルモジュールの1つに、反復可能なデータ構造(リンクリスト、配列など)に格納されたデータのセットがあり、それらをprocを通してユーザー状態に出力し、catなどを通してそれらを表示したいとします。やり方簡単にするために、データのリンクリストがあるとすると、リンクリストの先頭はlist_headという変数で指し示され、それ自体は読み書き可能なスピンロックで保護されています。リンクリストノードの構造は次のとおりです。

構造ノード{

構造ノード* next;

int num;

};

struct node * list_head; //チェインテーブルヘッダ

DEFINE_RWLOCK(list_lock); //読み書きスピンロックを定義して初期化します。

seq_fileは、反復のための関数ポインタのセットを定義します。これはC ++の順方向反復子のように機能しますが、ノード情報を出力するためのshowというメ​​ンバを持ちます。この関数ポインタのセットは、次のようにstruct seq_operationsという構造体で宣言されています。

struct seq_operations {
(* start)(struct seq_file * m、loff_t * pos);

void(* stop)(struct seq_file * m、void * v);

void *(* next)(struct seq_file * m、void * v、loff_t * pos); Br>

int(* show)(struct seq_file * m、void * v);

};

startはリソースの取得と初期化作業を行うことができます、かなりc ++のコンストラクタです。ロールとその戻り値は、最初の呼び出しと次の呼び出しの2番目のパラメーターとして渡され、そのたびにnextとshowが呼び出され、戻り値がNULLの場合はstart、直接呼び出しがstopの場合はshowとなりません。次へ出力するヘッダがある場合は、SEQ_START_TOKENカーネルに戻ることができます:

#define SEQ_START_TOKEN((void *)1)

nextの戻り値はshowおよびnextの呼び出しとして使用されます。 nextの2番目の引数(つまりv)が渡され、nextがNULLを返すとstopが呼び出されます。

stopの役割は、C ++クラスのデストラクタの役割と似ており、リソースのクリーンアップと戻り操作を担当します。

show関数は正しく0を返し、エラーは対応するエラーコードを返します。

出力情報は一度にカーネルによって割り当てられたバッファよりも大きいので(具体的な理由、次回seq_readや他の関数の実装について書くときなど)、start、show、nextのようになります。 、stopは複数回呼び出すことができます。これは、startとnextの3番目のパラメーターposを区別するために必要です。そのため、それらの呼び出しの順序は、開始 - >表示 - >次 - >表示 - >次 - >表示 - > ... - >次へ - >停止と記述することができます。

次のようにすることもできます(開始停止は複数回呼び出されます):start-> show-> next-> show-> next-> ...-> next-> > stop-> start-> show-> next ...-> next->停止します。これらの反復関数は、この例では次のように定義できます。

static void * my_start(struct seq_file * m、l loff_t * pos)

{

int i = 1;

struct node * tmp_entry;

read_lock_bh(list_lock); //読み書きスピンロックを取得します。

if(* pos == 0){

return SEQ_START_TOKEN;

}

for(tmp_entry = list_head; tmp_entry!= NULL; tmp_entry = tmp-entry-> next){

if(i == * pos)

return tmp_entry;

++ i;

}

return NULL;

}

static void my_stop(struct seq_file * m、void * v)

{
read_unlock_bh(tmp_lock); //スピンロックを解除する

seq_printf(m、 " \\ n \\ n -------------データ情報の終わり---------------------------";);

}

static void * my_next(struct seq_file * m、void * v、loff_t * pos)

{

++ * Pos;

return(SEQ_START_TOKEN == v)?list_head:((struct node *)v) - &g t; next;

}

static int my_show(struct seq_file * m、void * v)

{

struct node * tmp_entry;

static int line_count = 0;

if(SEQ_START_TOKEN == v){

seq_printf(m、" \\ n \\ n ----------) ---データ情報の開始--------------------------- \\ n \\ n");

} else {< Br>

tmp_entry =(struct node *)v;

seq_file(m、"%d"、tmp_entry-> num);

if(++ line_count = = 10){//1行で10個のデータが出力されます。

seq_printf(m、" \\ n");

line_count = 0;

}

}

return 0;

}

次に、struct seq_operationsを次のように定義します。

static const struct seq_operations my_seq_ops = {

.start = my_start、

.next = my_next、

.stop = my_stop、

.show = my_show、

};

この時点で、my_seq_opsのアドレスをカーネルに出力する関数も定義する必要があります。次のように、

static int proc_my_test_open((struct inode * inode、struct file * file))

{

return seq_open(file、& my_seq_ops);
<最後にstruct file_operations構造体を定義すると、proc_my_test_openがカーネルに渡され、proc_createが呼び出されてprocディレクトリが作成されました。コードは次のとおりです。

static const struct file_operations my_file_ops = {

.owner = THIS_MODULE、

.open = proc_my_test_open、

.read = seq_read、< Br>

.llseek = seq_lseek、

.release = seq_release、

};

my_file_opsproc_create(" my_test"、0、NULL、& my_file_ops);

実際には、単純な出力のために、あなたは単にshow関数を定義することができます、そしてここで我々のseq_openの代わりにsingle_openを通して、この方法は比較的簡単です、特定の方法はgoogleです。

Copyright © Windowsの知識 All Rights Reserved