Notes d'étude sur le développement de pilotes Linux [10]: notification asynchrone Linux

table des matières

1. Signal

Deuxièmement, la connexion et la différence entre les E / S synchrones, les E / S asynchrones, les E / S bloquantes et les E / S non bloquantes

Troisièmement, le processus de réalisation

1. Application

2. Pilote


1. Signal

Examinons d'abord "l'interruption". L'interruption est un mécanisme asynchrone fourni par le processeur. Après avoir configuré l'interruption, nous pouvons laisser le processeur gérer d'autres choses. Lorsque l'interruption se produit, elle déclenchera la fonction de service d'interruption que nous avons définie à l'avance. , Effectuez un traitement spécifique dans la fonction de service d'interruption. Une fois l'interruption utilisée, le processeur n'a pas besoin de vérifier si le bouton est enfoncé à tout moment, car l'interruption sera automatiquement déclenchée après avoir appuyé sur le bouton.

De même, les applications Linux peuvent accéder au périphérique d'entraînement de deux manières: bloquante ou non bloquante

  1. En mode de blocage, l'application sera dans un état dormant, en attendant que le périphérique d'entraînement soit disponible
  2. En mode non bloquant, il interrogera en permanence la fonction d'interrogation pour vérifier si le fichier de périphérique du lecteur peut être utilisé

Le signal est similaire à "l'interruption" utilisée sur notre matériel, mais le signal est au niveau logiciel. Il peut être considéré comme une simulation d'interruption au niveau du logiciel. Le pilote peut signaler qu'il est accessible en envoyant activement un signal au programme d'application. Une fois que le programme d'application a obtenu le signal, il peut lire ou écrire des données à partir du dispositif d'entraînement . L'ensemble du processus équivaut au fait que le programme d'application reçoit une interruption envoyée par le pilote, puis le programme d'application répond à l'interruption. Pendant tout le processus, le programme d'application ne demande pas si le lecteur est accessible, tout est dit par le lecteur lui-même Pour l'application.

Le cœur de la notification asynchrone est le signal. Tous les signaux pris en charge par Linux sont définis dans le fichier arch / xtensa / include / uapi / asm / signal.h . Ces signaux sont les suivants:

#define SIGHUP		 1
#define SIGINT		 2
#define SIGQUIT		 3
#define SIGILL		 4
#define SIGTRAP		 5
#define SIGABRT		 6
#define SIGIOT		 6
#define SIGBUS		 7
#define SIGFPE		 8
#define SIGKILL		 9
#define SIGUSR1		10
#define SIGSEGV		11
#define SIGUSR2		12
#define SIGPIPE		13
#define SIGALRM		14
#define SIGTERM		15
#define SIGSTKFLT	16
#define SIGCHLD		17
#define SIGCONT		18
#define SIGSTOP		19
#define SIGTSTP		20
#define SIGTTIN		21
#define SIGTTOU		22
#define SIGURG		23
#define SIGXCPU		24
#define SIGXFSZ		25
#define SIGVTALRM	26
#define SIGPROF		27
#define SIGWINCH	28
#define SIGIO		29
#define SIGPOLL		SIGIO
/*
#define SIGLOST		29
*/
#define SIGPWR		30
#define SIGSYS		31
#define	SIGUNUSED	31

/* These should not be considered constants from userland.  */
#define SIGRTMIN	32
#define SIGRTMAX	_NSIG

#define SIGSWI		32

Deuxièmement, la connexion et la différence entre les E / S synchrones, les E / S asynchrones, les E / S bloquantes et les E / S non bloquantes

https://www.cnblogs.com/euphie/p/6376508.html

Troisièmement, le processus de réalisation

Code source complet du pilote: https://github.com/denghengli/linux_driver/tree/master/17_fasync

1. Application

Pour utiliser la notification asynchrone dans votre application, vous devez ajouter du contenu:

(1) Enregistrer une nouvelle fonction de traitement des nombres

(2) Indiquez au noyau le numéro de processus de cette application

(3) Activer la notification asynchrone

static void sigio_signal_func(int signum)
{
    ...
}
/*
*argc 应用程序参数个数
*argv 具体的参数内容,字符串形式
*/
int main(int argc, char *argv[]) 
{
    ...
    signal(SIGIO, sigio_signal_func);/*设置sigio的处理函数*/
    /*int fcntl (int __fd, int __cmd, ...);*/
    fcntl(fd, F_SETOWN, getpid());/*设置当前进程接收SIGIO信号*/
    flags = fcntl(fd, F_GETFL);/*获取当前文件标志*/
    fcntl(fd, F_SETFL, flags | FASYNC);/*设置当前文件标志,开启异步通知*/
    ...
    return 0;
}

2. Pilote

(1) Lorsque le périphérique est accessible, le pilote doit envoyer un signal à l'application via la fonction kill_fasync , ce qui équivaut à générer une "interruption"

void kill_fasync (struct fasync_struct ** fp, int sig, bande int)

fp : La fasync_struct à utiliser.

sig le signal à envoyer.

Défini sur POLL_IN lorsque la bande est lisible et POLL_OUT lorsqu'elle peut être écrite.

Valeur de retour : aucune.

(2) Ecrivez la fonction fasync. Lorsque l'application change l'indicateur fasync via fcntl (fd, F_SETFL, flags | FASYNC) , la fonction fasync du jeu d'opérations file_operations du pilote sera exécutée et la structure de contrôle fasync doit être initialisée dans cette fonction

/* key设备结构体 */
struct key_dev{
    ...
	/*异步结构体 --- 异步通知*/
	struct fasync_struct *fasync_queue;
};

/*定时器回调函数*/
static void timer_func(unsigned long arg)
{
    struct key_dev *dev = (struct key_dev*)arg;
    ...
    if (dev->fasync_queue){	/*有效的按键过程,相应层发送信号实现异步通知*/
            /*SIFIO为发送的信号,POLL_IO表示可读,POLL_OUT表示可写*/
            kill_fasync(&dev->fasync_queue, SIGIO, POLL_IN);
        }
	}
}

static int key_release(struct inode *inode, struct file *filp)
{
	int i = 0;
	struct key_dev *dev = filp->private_data;
    ...
	/*删除fasync结构体*/
	return fasync_helper(-1, filp, 0, &dev->fasync_queue);
}

static int key_fasync(int fd, struct file *filp, int on)
{
	struct key_dev *dev = filp->private_data;

	/*初始化fasync结构体*/
	return fasync_helper(fd, filp, on, &dev->fasync_queue);
}

/* 设备操作函数 */
static struct file_operations key_fops = {
    ...
	.fasync = key_fasync,
};

 

 

Je suppose que tu aimes

Origine blog.csdn.net/m0_37845735/article/details/107307462
conseillé
Classement