Queue processing interrupt bottom half

If there was one word to describe the function of the bottom half, it would be "delayed execution"

 There are three ways to implement the bottom half of the interrupt:

using soft interrupt

Using tasklet microthreading

adopt queue

 

Because several interrupt processing methods encountered now are implemented using work queues, the queues are mainly explained here:

 The work queue 

      In the Linux kernel, there are several ways to handle the bottom half (or deferred execution), including BH ( bottom  half ), soft interrupts, Tasklets and work queues, etc. In the 2.6 kernel, the famous BH processing was abolished, and a more convenient work queue was added. The convenience of the work queue is that it pushes the work back and hands it over to a kernel thread for execution . This kernel thread will always execute in the context of the process, so it can easily hold a semaphore ( semaphore ), of course . Sleep is allowed .

      The processing of the work queue by the kernel is done by worker threads . The worker thread is generally in a sleep state. After we register the work that needs to be delayed in the work queue, waking up the worker thread will traverse each pending work in the work queue and execute the work_struct in the work queue structure. func function .

There are two concepts involved here: worker threads and work queues.

Let's start by looking at the work queues we care about most.

      struct work_struct*delayed_work;

      INIT_WORK(delayed_work,delayed_work_handler, data);

      schedule_work(delayed_work);

      delayed_work is the work queue we declared; the work queue is initialized through INIT_WORK , delayed_work_handler is the processing function of the work queue, and data is the parameter passed to the processing function; finally, schedule_work is called to wake up the worker thread to process the delayed work. If you need to perform work after a delay, you can call:

      schedule_delayed_work(delayed_work,delay);    //delay is the number of beats that need to be delayed

      There is another way to create a work queue statically:

      DECLARE_WORK(name, void (*func) (void *),void *data);

      For the most part, we've learned that this is enough. Worker threads can be safely handed over to the kernel for completion.

There are two ways to use worker threads. One is to directly use a default worker thread envents/n corresponding to each CPU in the kernel ( n represents the serial number of the CPU , starting from 0 );

The other is to create a dedicated worker thread yourself.

In general, driver developers don't need to care about worker threads, the default worker threads can do just fine. If the default queue does not meet the requirements, creating a worker thread yourself is also very simple, just call:

      structworkqueue_struct *create_workqueue(const char *name);

      Use the following functions when scheduling:

      intqueue_work(struct workqueue_struct *wq, struct work_struct *work);

      or

      intqueue_delayed_work(struct workqueue_struct *wq, struct work_struct

      *work,unsigned long delay);

      They are similar to schedule_work() and schedule_delayed_work() .

 

2. Waiting queue

 

staticDECLARE_WAIT_QUEUE_HEAD(waiter); // Define and initialize waiter

   wake_up_interruptible(&waiter); // Wake up waiting queue

 

   set_current_state(TASK_INTERRUPTIBLE);        

   wait_event_interruptible(waiter, tpd_flag != 0); // Judging execution conditions

 

 

Differences between Linux work queues and wait queues:

A simple conceptual distinction between these two confusing queues: 

     等待队列在内核中有很多用途,尤其适合用于中断处理,进程同步及定时。我们在这里只说,进程经常必须等待某些事件的发生。例如,等待一个磁盘操作的终止,等待释放系统资源,或者等待时间经过固定的间隔。 

         等待队列实现了在事件上的条件等待,希望等待特定事件的进程把自己放进合适的等待队列,并放弃控制权。因此。等待队列表示一组睡眠的进程,当某一条件为真时,由内核唤醒它们。 

等待队列由循环链表实现,其元素包括指向进程描述符的指针。每个等待队列都有一个等待队列头,等待队列头是一个类型为wait_queue_head_t的数据结构。 

等待队列链表的每个元素代表一个睡眠进程,该进程等待某一事件的发生,它的描述符地址存放在task字段中。然而,要唤醒等待队列中所有的进程有时并不方便。例如,如果两个或多个进程在等待互斥访问某一个要释放的资源,仅唤醒等待队列中一个才有意义。这个进程占有资源,而其他进程继续睡眠可以用DECLARE_WAIT_QUEUE_HEAD(name)宏定义一个新的等待队列,该宏静态地声明和初始化名为name的等待队列头变量。 init_waitqueue_head()函数用于初始化已动态分配的wait queue head变量等待队列可以通过DECLARE_WAITQUEUE()静态创建,也可以用init_waitqueue_head()动态创建。进程把自己放入等待队列并设置成不可执行状态。 

 

工作队列,workqueue,它允许内核代码来请求在将来某个时间调用一个函数。用来处理不是很紧急事件的回调方式处理方法。

工作队列的作用就是把工作推后,交由一个内核线程去执行,更直接的说就是如果您写了一个函数,而您现在不想马上执行它,您想在将来某个时刻去执行它,那您用工作队列准没错 

如果需要用一个可以重新调度的实体来执行你的下半部处理,也应该使用工作队列。它是唯一能在进程上下文运行的下半部实现的机制,也只有它才可以睡眠。这意味着在需要获得大量的内存时、在需要获取信号量时,在需要执行阻塞式的I/O操作时,它都会非常有用。

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326297029&siteId=291194637