linux駆動学習の非同期通知
8428 ワード
http://blog.csdn.net/fontlose/article/details/8257201
非同期通知は、デバイスのステータスが変更された後にアプリケーションにアクティブに通知することであり、アプリケーションがデバイスをブロックしたりクエリーしたりする必要はありません.カーネルの非同期通知を信号で処理し、poll selectを最後に使用してデバイスの読み取り可能な状態を問合せた場合、以下の例は同様であり、デバイスにデータがある場合、アプリケーションにデータの読み取りをアクティブに通知するのとは異なる.
アプリケーションのCコードは簡単で、主に信号の処理方式を設定して、カーネルはデータがある時SIGIO信号を受け取って、アプリケーションは自動的にsignal設定の関数を呼び出してデータを読みます.
main.c
[cpp] view plain copy print ?
#include #include
#include #include
unsigned char rdBuf[1024]; int fd;
void hand_signal(int sign) {
if(sign==SIGIO) {
if (read(fd,rdBuf,1024)>0) printf("read data:%s",rdBuf);
} }
int main (int *argc,char**argv)
{ int fd,flags;
/*SIGIO信号の処理 駆動例でデータを受信したときにアプリケーションに送信するのもSIGIO信号*/ signal(SIGIO,hand_signal);
fd=open("/dev/moduledev60",O_RDWR); if(fd<0)
{ printf("open file error");
return -1; }
/*ドライバ信号が誰に送信されるかを伝える 3番目のパラメータはプロセス番号*/です.
fcntl(fd, F_SETOWN, getpid());
/*FASYNCの設定 実行後に駆動されるfasyncメソッドが呼び出されます*/ flags = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, flags | FASYNC);
while(1); }
プライマリコードを駆動し、読み取り操作は最後に書き込まれた文字列のみを返し、書き込み操作後に設定されたプロセスにSIGIO信号を送信する
[cpp] view plain copy print ?
struct file_operations ops= {
.owner=THIS_MODULE , .read =fileops_read ,
.write=fileops_write, .fasync=fileops_fasync,
.close=fileops_release };
int fileops_release(struct inode *inode,struct file *filp) {
printk(KERN_ALERT "fileops_release"); fileops_fasync(-1,filp,0); //3番目のパラメータが0の場合、最初のパラメータは使用されず、申請のメモリを解放します.
return 0; }
ssize_t fileops_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)
{ unsigned int len;
if(rdFlag==0) return 0; len=strlen(rdBuf);
copy_to_user(buff,rdBuf,len); rdFlag=0;
return len; }
ssize_t fileops_write(struct file *filp, const char __user *buff, size_t count, loff_t *offp)
{ copy_from_user(rdBuf,buff,count);
rdBuf[count]=0; rdFlag=1;
kill_fasync(&fasync_queue,SIGIO ,POLL_IN); //データ書き込みあり 設定されたプロセスにSIGIO信号を送信 printk(KERN_ALERT "signal %d ",SIGIO);
return count; }
int fileops_fasync (int fd, struct file *filp, int mode)
{ int res=fasync_helper(fd,filp,mode,&fasync_queue); //fasync_queueの初期化
printk(KERN_ALERT "filp %x",(int)filp); if(res<0) return res;
else return 0; }
テスト結果
[plain] view plain copy print ?
プリコンパイルロードドライバ [root@localhost ctest]# insmod moddev.ko
アプリケーションの実行
[root@localhost ctest]# ./main 別の端末を開いてデバイスにデータを書き込む [root@localhost ctest]# echo 111 > /dev/moduledev60
出力を適用し、データが書き込まれるたびに、駆動通知アプリケーション読取装置 [root@localhost ctest]# ./main
read data:111
[cpp] view plain copy print ?
fasync_helperソースを添付/*
* fasync_helper() is used by some character device drivers (mainly mice)
* to set up the fasync queue. It returns negative on error, 0 if it did * no changes and positive if it added/deleted the entry.
*/ int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fapp)
{ /*この関数は、非同期通知構造チェーンテーブルを作成および解放するための線形テーブルを維持します*/ struct fasync_struct *fa, **fp;
struct fasync_struct *new = NULL; int result = 0;
if (on) {
new = kmem_cache_alloc(fasync_cache, GFP_KERNEL); //非同期通知構造変数の申請 if (!new)
return -ENOMEM; }
write_lock_irq(&fasync_lock); for (fp = fapp; (fa = *fp) != NULL; fp = &fa->fa_next) {
if (fa->fa_file == filp) { if(on) //filpノードは既に存在します
fa->fa_fd = fd; kmem_cache_free(fasync_cache, new);
} else //見つかったノードを解放する *fp = fa->fa_next;
kmem_cache_free(fasync_cache, fa); result = 1;
} goto out;
} }
if (on) //申請したノードをチェーンテーブルに追加
new->magic = FASYNC_MAGIC; new->fa_file = filp;
new->fa_fd = fd; new->fa_next = *fapp;
*fapp = new; result = 1;
} out:
write_unlock_irq(&fasync_lock); return result;
}
非同期通知は、デバイスのステータスが変更された後にアプリケーションにアクティブに通知することであり、アプリケーションがデバイスをブロックしたりクエリーしたりする必要はありません.カーネルの非同期通知を信号で処理し、poll selectを最後に使用してデバイスの読み取り可能な状態を問合せた場合、以下の例は同様であり、デバイスにデータがある場合、アプリケーションにデータの読み取りをアクティブに通知するのとは異なる.
アプリケーションのCコードは簡単で、主に信号の処理方式を設定して、カーネルはデータがある時SIGIO信号を受け取って、アプリケーションは自動的にsignal設定の関数を呼び出してデータを読みます.
main.c
[cpp] view plain copy print ?
#include
#include
unsigned char rdBuf[1024];
void hand_signal(int sign)
if(sign==SIGIO)
if (read(fd,rdBuf,1024)>0)
}
{
/*SIGIO信号の処理 駆動例でデータを受信したときにアプリケーションに送信するのもSIGIO信号*/
fd=open("/dev/moduledev60",O_RDWR);
{
return -1;
fcntl(fd, F_SETOWN, getpid());
/*FASYNCの設定 実行後に駆動されるfasyncメソッドが呼び出されます*/
fcntl(fd, F_SETFL, flags | FASYNC);
while(1);
#include <stdio.h>
#include <fcntl.h>
#include <signal.h>
#include <stdlib.h>
unsigned char rdBuf[1024];
int fd;
void hand_signal(int sign)
{
if(sign==SIGIO)
{
if (read(fd,rdBuf,1024)>0)
printf("read data:%s
",rdBuf);
}
}
int main (int *argc,char**argv)
{
int fd,flags;
/* SIGIO SIGIO */
signal(SIGIO,hand_signal);
fd=open("/dev/moduledev60",O_RDWR);
if(fd<0)
{
printf("open file error
");
return -1;
}
/* */
fcntl(fd, F_SETOWN, getpid());
/* FASYNC fasync */
flags = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, flags | FASYNC);
while(1);
}
プライマリコードを駆動し、読み取り操作は最後に書き込まれた文字列のみを返し、書き込み操作後に設定されたプロセスにSIGIO信号を送信する
[cpp] view plain copy print ?
struct file_operations ops=
.owner=THIS_MODULE ,
.write=fileops_write,
.close=fileops_release
int fileops_release(struct inode *inode,struct file *filp)
printk(KERN_ALERT "fileops_release");
return 0;
{
if(rdFlag==0) return 0;
copy_to_user(buff,rdBuf,len);
return len;
{
rdBuf[count]=0;
kill_fasync(&fasync_queue,SIGIO ,POLL_IN); //データ書き込みあり 設定されたプロセスにSIGIO信号を送信
return count;
{
printk(KERN_ALERT "filp %x",(int)filp);
else return 0;
struct file_operations ops=
{
.owner=THIS_MODULE ,
.read =fileops_read ,
.write=fileops_write,
.fasync=fileops_fasync,
.close=fileops_release
};
int fileops_release(struct inode *inode,struct file *filp)
{
printk(KERN_ALERT "fileops_release
");
fileops_fasync(-1,filp,0); // 0 , ,
return 0;
}
ssize_t fileops_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)
{
unsigned int len;
if(rdFlag==0) return 0;
len=strlen(rdBuf);
copy_to_user(buff,rdBuf,len);
rdFlag=0;
return len;
}
ssize_t fileops_write(struct file *filp, const char __user *buff, size_t count, loff_t *offp)
{
copy_from_user(rdBuf,buff,count);
rdBuf[count]=0;
rdFlag=1;
kill_fasync(&fasync_queue,SIGIO ,POLL_IN); // SIGIO
printk(KERN_ALERT "signal %d
",SIGIO);
return count;
}
int fileops_fasync (int fd, struct file *filp, int mode)
{
int res=fasync_helper(fd,filp,mode,&fasync_queue); // fasync_queue
printk(KERN_ALERT "filp %x
",(int)filp);
if(res<0) return res;
else return 0;
}
テスト結果
[plain] view plain copy print ?
プリコンパイルロードドライバ
[root@localhost ctest]# ./main 別の端末を開いてデバイスにデータを書き込む
出力を適用し、データが書き込まれるたびに、駆動通知アプリケーション読取装置
read data:111
[root@localhost ctest]# insmod moddev.ko
[root@localhost ctest]# ./main
[root@localhost ctest]# echo 111 > /dev/moduledev60
, ,
[root@localhost ctest]# ./main
read data:111
[cpp] view plain copy print ?
fasync_helperソースを添付
* to set up the fasync queue. It returns negative on error, 0 if it did
*/
{ /*この関数は、非同期通知構造チェーンテーブルを作成および解放するための線形テーブルを維持します*/
struct fasync_struct *new = NULL;
new = kmem_cache_alloc(fasync_cache, GFP_KERNEL); //非同期通知構造変数の申請
return -ENOMEM;
write_lock_irq(&fasync_lock);
if (fa->fa_file == filp) {
fa->fa_fd = fd;
} else //見つかったノードを解放する
kmem_cache_free(fasync_cache, fa);
}
}
new->magic = FASYNC_MAGIC;
new->fa_fd = fd;
*fapp = new;
}
write_unlock_irq(&fasync_lock);
}