[Linux driver] Chapter 6 advanced character driver operations-blocking I/O

Source: Internet
Author: User

 

Preface: If read/write in the driver method is unavailable, the user may call read. When the output buffer is full, the device is not ready to accept the data, in this case, the driver can block the process and put it in sleep state until the conditions are met.


1. Sleep


When a process is sleep, it is marked as a special State and moved from the running queue of the scheduler until it is modified in some cases, the process is scheduled on any CPU.
In Linux, there are two rules to ensure process security enters the sleep state:
 

1) never sleep in atomic context.

Note: Atomic context: concurrent access is not allowed when multiple steps are executed. You cannot have a spin lock, seqlock, or RCU sleep when locking. Process 1 is valid when having a semaphore, but make sure process 1 has a semaphore and will not block the process 2 that wakes us up.

 
2) do not make any assumptions about the wake-up status. check to ensure that the conditions we are waiting for are true.

There are two methods to initialize a waiting queue:

 
1) static
Declare_wait_queue_head (my_queue );
2) Dynamic
Wait_queue_head_t my_queue;

Init_waitqueue_head (& my_queue );


A waiting queue is managed by a wait_queue_head_t struct, which is defined in <Linux/Wait. H>.

struct __wait_queue_head {    spinlock_t lock;    struct list_head task_list;};typedef struct __wait_queue_head wait_queue_head_t;


2. Simple sleep

Waiting queue: A process linked list that contains all processes waiting for a specific event.
In Linux, a waiting queue is managed by a "wait queue head" and its type is wait_queue_head_t, which is defined in <Linux/Wait. H>.

 
Sleep macro: wait_event (queue, condition); // The queue is the waiting queue header. The condition is of the boolea type.
Wait_event_interruptible (queue, condition); // can interrupt sleep
Wait_event_timeout (queue, condition, timeout); // The time for waiting.
Wait_event_interruptible_timeout (queue, condition, timeout );

The call of the macro above will cause the call process to be blocked if the condition is not met, and the macro evaluates the condition value before and after hibernation. From the name, we can see that the macro with interruptible can interrupt sleep, if a non-zero value is returned, the driver returns-erestartsys. the macro with timeout indicates that at the given time, the macro will return 0.

Wake-up function:

Void wake_up (wait_queue_head_t * Queue );
Void wake_up_interruptible (wait_queue_head_t * Queue );

Wake_up will wake up all the processes on the queue, while wake_up_interruptible will only wake up the interrupted processes.

Iii. Advanced sleep

How does a process sleep?

Step 1: allocate and initialize a wait_queue_t structure, and then add it to the corresponding waiting queue.
 

Step 2: Use the set_current_state (INT new_state) function to set the process status.

The driver is mainly concerned with the Process status task_running (runable), task_interruptible (resumable sleep), and task_uninterrputible (non-disruptive sleep ).


Step 3: call schedule (). Remember to check the sleep conditions before calling. If you do not check, the race state will be introduced: if there are other threads trying to wake you up when you are busy with the above process, you may miss it.

The classic check code is as follows:


If (! Condition)

Schedule ();

4. Manual sleep <Linux/sched. h> contains the required Definitions

(1) Create and initialize a waiting queue. It is often defined by a macro:
Define_wait (my_wait); // name is the name of the waiting queue entry.

Method 2:

Wait_queue_t my_wait;
Init_wait (& my_wait );

A common practice is to put define_wait on the top of the loop to sleep.

(2) Add the waiting queue entry to the queue and set the process status:
Void prepare_to_wait (wait_queue_head_t * queue, wait_queue_t * Wait, int State );
Queue waiting queue Header

WaitProcess entry

New State of the state process: task_interruptible (can interrupt sleep, recommended) or task_uninterruptible (cannot interrupt sleep, not recommended ).

(3) call schedule after checking whether sleep is required
Schedule ();

(4) When schedule returns, the cleanup time is reached:
 

Void finish_wait (wait_queue_head_t * queue, wait_queue_t * Wait );

The underlying source code of wait_event (queue, condition) and wait_event_interruptible (queue, condition) in simple sleep will find that they are only a combination of functions in manual sleep. It is better to use wait_event if you are in trouble.





V,Exclusive waiting

When a process calls wake_up on the waiting queue, all the processes waiting on the queue are set to run. This is a correct practice in many cases. However, sometimes only one wake-up process will successfully obtain the required resources, and the rest will sleep again. In this case, if the number of processes in the waiting queue is large, this may seriously reduce system performance. Therefore, the kernel developer adds an exclusive waiting option.

The exclusive wait process differs from the normal sleep process:

1) The wq_flag_exclusive flag is set for the waiting queue entry and added to the end of the waiting queue. processes without this flag are added to the waiting queue header.

2) When wake_up is called on a waiting queue, it will wake up the first process with the wq_flag_exclusive flag and then wake up other processes.

When will an exclusive waiting process be used? Consider the following two conditions:

1) there is severe competition for a certain resource.

2) Wake up a single process to completely consume this resource

Vi. Wake-up functions
It is seldom necessary to call wake-up functions other than wake_up_interruptible, but for the sake of completeness, here is the entire set:
Wake_up (wait_queue_head_t * Queue );//Wake up each non-exclusive waiting process and one exclusive waiting process in the queue
Wake_up_interruptible (wait_queue_head_t * Queue );//Process that is not interrupted or sleep. They wake up and schedule one or more processes before returning (if they are called from an atomic context, this will not happen)

Wake_up_nr (wait_queue_head_t * queue, int nr );
Wake_up_interruptible_nr (wait_queue_head_t * queue, int nr );

These functions are similar to wake_up, except that they can wake up to Nr exclusive waits, not just one. Note that passing 0 is interpreted as a request for all mutex waits to be awakened

Wake_up_all (wait_queue_head_t * Queue );
Wake_up_interruptible_all (wait_queue_head_t * Queue );

This kind of wake_up will wake up all processes, regardless of whether they have exclusive waits (the type of interruptions still skips the processes that are waiting for non-disruptive waits)

Wake_up_interruptible_sync (wait_queue_head_t * Queue );
A wake-up process may seize the current process and be scheduled to the processor before wake_up returns. However, you can use the "synchronization" variant of wake_up_interruptible if you do not need to be scheduled out of the processor. this function is most commonly used when the caller first needs to complete a small amount of work and does not want to be scheduled out of the processor.

7. Blocking and non-blocking operations

Set non-blocking I/O

Explicit non-blocking I/O is determined by the o_nonblock flag in filp-> f_flags. To maintain compatibility with the System V code, the o_ndelay and o_nonblock indicate that, non-blocking Io read and write will return-eagain.

There are two ways for an application to develop non-blocking IO:

1) it is specified during open, which may be blocked for a long time in open call.

2) Call the fcntl function. The specific usage can be found online. I will not list it here.

Standard semantics of blocking operations

If a process calls read but does not have readable data, the process is blocked. When the data arrives, the process is awakened and the data is returned to the caller, even if the data is less than count; if a process calls write but the buffer is full, the process must be blocked and sleep in a different waiting queue from the read process. When the buffer is idle, the process is awakened and data is successfully written, even if the number of bytes is less than count.

Scullp: An Example of Io Blocking

static ssize_t scull_p_read (struct file *filp, char __user *buf, size_t count, loff_t *f_pos){        struct scull_pipe *dev = filp->private_data;        if (down_interruptible(&dev->sem))                return -ERESTARTSYS;        while (dev->rp == dev->wp) { /* nothing to read */                up(&dev->sem); /* release the lock */                if (filp->f_flags & O_NONBLOCK)                        return -EAGAIN;                PDEBUG("\"%s\" reading: going to sleep\n", current->comm);                if (wait_event_interruptible(dev->inq, (dev->rp != dev->wp)))                        return -ERESTARTSYS; /* signal: tell the fs layer to handle it */                if (down_interruptible(&dev->sem))                        return -ERESTARTSYS;        }        /* ok, data is there, return something */        if (dev->wp > dev->rp)                count = min(count, (size_t)(dev->wp - dev->rp));        else /* the write pointer has wrapped, return data up to dev->end */                count = min(count, (size_t)(dev->end - dev->rp));        if (copy_to_user(buf, dev->rp, count)) {                up (&dev->sem);                return -EFAULT;        }        dev->rp += count;        if (dev->rp == dev->end)                dev->rp = dev->buffer; /* wrapped */        up (&dev->sem);        /* finally, awake any writers and return */       wake_up_interruptible(&dev->outq);        PDEBUG("\"%s\" did read %li bytes\n",current->comm, (long)count);        return count;}
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.