LINUX driving mechanism of asynchronous communication FSYNC

The asynchronous communication driver LINUX


Long time no write notes with a CSDN, before all with the proper way cloud notes, however markdown support is not so good, so try to write how CSDN blog effects

Brief introduction

For before pressing the key driver, there are three prior treatment

  • Query mode :
    This mode CPU usage efficiency is very high, it is clearly not desirable method
  • Interrupt mode :
    in this way should combine to make the process of sleep, wake up approach, you can get a high processing efficiency
  • poll mode :
    in this way have combined interrupt, it can monitor the occurrence of an event or not multiple devices, if the event being monitored occurs or exceeds a certain time, the process will be awakened, to be returned to a specific value user program that allows users to select their own treatment program.

This user program had to stop three ways to read the driver's interface is a proactive way, the user process can not do other things, that the question now is whether there is a way, so that the user can process perform other work until such time as there is an event (interruption) occurs before notifying the user program to deal with it?

Yes, this approach is there is asynchronous notification

Examples of simple applications

The following Reference Examples Wei video Higashiyama,

#include <stdio.h>
#include <signal.h>

void my_signal_fun( int signum ){
	static int cnt;
	printf("signal = %d, %d times\n",signum, ++cnt);/*signums信号编好,cnt记录进如该信号处理函数的次数*/
}
	
int main( int argc , char **argv ){
	signal( SIGUSR1, my_signal_fun );
	
	while(1){
	/*可以做其他的工作,这里先让他休眠*/
		sleep(1000);
	}
	return 0
}	

Explanation:
signal (SIGUSER1, my_signal_fun); man signal can be entered in the shell of this function see some
basic usage,

SIGNAL(2)                  Linux Programmer's Manual                 SIGNAL(2)

NAME
       signal - ANSI C signal handling

SYNOPSIS
       #include <signal.h>

       typedef void (*sighandler_t)(int);

       sighandler_t signal(int signum, sighandler_t handler);

DESCRIPTION
       The behavior of signal() varies across UNIX versions, and has also var‐
       ied historically across different versions of Linux.   Avoid  its  use:
       use sigaction(2) instead.  See Portability below.

       signal() sets the disposition of the signal signum to handler, which is
       either SIG_IGN, SIG_DFL, or the address of a  programmer-defined  func‐
       tion (a "signal handler").

       If  the signal signum is delivered to the process, then one of the fol‐
       lowing happens:

       *  If the disposition is set to SIG_IGN, then the signal is ignored.

       *  If the disposition is set to SIG_DFL, then the default action  asso‐
          ciated with the signal (see signal(7)) occurs.

       *  If  the disposition is set to a function, then first either the dis‐
          position is reset to SIG_DFL, or the signal is blocked  (see  Porta‐
          bility  below), and then handler is called with argument signum.  If
          invocation of the handler caused the signal to be blocked, then  the
          signal is unblocked upon return from the handler.

       The signals SIGKILL and SIGSTOP cannot be caught or ignored.

RETURN VALUE
       signal()  returns  the previous value of the signal handler, or SIG_ERR
       on error.

This function returns a set of the current process receives a signal corresponding to the signal number when corresponding handler.
typedef void (* sighandler_t) (int ); This statement defines a return value is void, the int parameter
a function pointer,

sighandler_t signal(int signum, sighandler_t handler);

This signal is a function prototype, the first parameter is the signal number and the second parameter is the processing corresponding to the function,
the normal value, then execution returns back pointer is changed handler, an error condition is returned SIG_ERR.

Compile this program and copied to the development board,

On the console, ps inquiry process number, then
enter the command

kill -USR1 837

Will return to the program in print statements
Here Insert Picture Description
after we send a signal to the program from the console SIGUSR1, the program would lay down procedures manual of the main program to perform pre-defined procedures that signal processing functions.

The advantage of this mechanism is that while waiting for an event and does not require blocking of waiting, but when the program can perform the main tasks, to send a signal by another process, let the program go to the corresponding signal processing flow, processed later, again execute the main flow. So one explanation, I felt interrupt mechanism exactly.

Analysis simple asynchronous communication process program key

We want the driver to send a signal to let the user program for processing.

The whole process is very simple, as follows:

  • When the button is pressed, a drive signal is sent to notify the application
  • Transferred to the application register signal processing functions, for processing.

user terminalTo finish things:

  • A signal processing function is defined
  • Sign up signal handler, linked to a signal
  • Tell drive, its own process number is how much information is sent to the driver in this process

== == driven end to accomplish something like this:

  • Gets the process ID of the user program
  • When the interrupt occurs, a signal is sent to the user program

User level code flow

What is the specific function to achieve it? First focus to the user program, the first two points have been resolved, and now need to be addressed is the third point, the user program in the end how to get their own process ID, and sends driver it? First on the code

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <poll.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>


/* fifthdrvtest 
*/
int fd;

void my_signal_fun(int signum)
{
 unsigned char key_val;
 read(fd, &key_val, 1);
 printf("key_val: 0x%x\n", key_val);
}

int main(int argc, char **argv)
{
 unsigned char key_val;
 int ret;
 int Oflags;

 signal(SIGIO, my_signal_fun);
 
 fd = open("/dev/buttons", O_RDWR);
 if (fd < 0)
 {
 	printf("can't open!\n");
 }

 fcntl(fd, F_SETOWN, getpid());
 
 Oflags = fcntl(fd, F_GETFL); 
 
 fcntl(fd, F_SETFL, Oflags | FASYNC);


 while (1)
 {
 	sleep(1000);
 }
 
 return 0;
}

Get your own PID, and sent to the driver's key code

 fcntl(fd, F_SETOWN, getpid());

Oflags = fcntl(fd, F_GETFL); 

fcntl(fd, F_SETFL, Oflags | FASYNC);

In particular usage console input man fcntl fcntl function can see, this function simply, it is the function of processing the file descriptor, more functional, now learning to use for several functions

So now it is to understand the meaning of F_SETOWN, F_GETFL, and FASYNC these identities,

Small found: in man which can enter vi similar Find command / name, these identifiers can be found quickly

- F_SETOWN (third parameter is Long) :
This identifies the group number setting process or process, or for receiving SIGIO SIGURG signals emitted by certain events which file descriptor fd, arg process ID assigned to the parameters. Process id is specified as a positive value, process group id is specified as a negative value. In most cases, it is the designated owner
Arg is set to getpid (2). So you can know

fcntl(fd, F_SETOWN, getpid());

This means that the current process ID, set to open this file descriptor has to go inside, in order to be able to receive the current process or SIGURG SIGIO signal.

- F_GETFL the F_SETFL
the fcntl function may change the nature of the file is already open, and if F_GETFL, the return value is a document of the state flag,
the F_SETFL can be used to change the state identification document,

Oflags = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, Oflags | FASYNC);

These two words are to read a file status, return to the oflags, then add a FASYNC oflags attribute, then set to the file, the file is equivalent to adding an identification of a FASYNC, FASYNC this very special properties, this It should be asynchronous notification attribute Once this property is set, will be the driver will call fsync function, my understanding is fcntl set up to identify the driver layer FASYNC will send an asynchronous notification to the future, so this call fsync driver layer function.

Code-driven layer

Two main points:

  • fsync function, after driving to the top send an asynchronous notification, eventually calls, fasync function driver layer
static struct fasync_struct *button_async;
static int fifth_drv_fasync (int fd, struct file *filp, int on)
{
	printk("driver: fifth_drv_fasync\n");
	return fasync_helper (fd, filp, on, &button_async);
}

Explanation: The first definition of a static fasync_struct structure pointer, in fact, it should be the head of a queue, and then call fasync_helper function, which, as defined in the kernel, I simply looked at the fasync_struct should be first initialize a structure, and then add to queue to go inside.

if (on) {
		new->magic = FASYNC_MAGIC;
		new->fa_file = filp;
		new->fa_fd = fd;
		new->fa_next = *fapp;
		*fapp = new;
		result = 1;
	}

Queue entry which contains the process ID added information, and file information pointer Clearly, when sending a signal, the head of the queue to use.

fasync_struct structure, and

  • A signal is sent when the interruption occurred, sending a message to the user process SIGIO

kill_fasync (&button_async, SIGIO, POLL_IN);

The first parameter is button_async, is an asynchronous function inside initialized in fasync notification queue, which contains the user process PID,
SIGIO, the signal number is to be sent. You can look inside the kernel source code


void __kill_fasync(struct fasync_struct *fa, int sig, int band)
{
	while (fa) {
		struct fown_struct * fown;
		if (fa->magic != FASYNC_MAGIC) {
			printk(KERN_ERR "kill_fasync: bad magic number in "
			       "fasync_struct!\n");
			return;
		}
		fown = &fa->fa_file->f_owner;
		/* Don't send SIGURG to processes which have not set a
		   queued signum: SIGURG has its own default signalling
		   mechanism. */
		if (!(sig == SIGURG && fown->signum == 0))
			send_sigio(fown, fa->fa_fd, band);
		fa = fa->fa_next;
	}
}

You can see kill_fasync calls send_sigio to send a signal, a signal will be sent through each one fasync queue are transmitted,
I think that even with a lot of processes to send messages at the same time.

  • Finally, it must be considered when closing the file, release function inside to free up resources, such as the fasync queue, learn a little, the source
    fasync_helper function can be used to release resources, as long as the parameter is set to 0 on the line.

Guess you like

Origin blog.csdn.net/ronaldo_hu/article/details/90719036