linux中断下文工作队列之共享工作队列(中断四)

  工作队列是操作系统中管理和调度异步任务执行的一种机制

一、工作队列介绍

  工作队列是实现中断下半部分的机制之一,是一种用于管理任务的数据结构或机制。它通常用于多线程,多进程或分布式系统中,用于协调和分配待处理的任务给可用的工作线程或工作进程。
  工作队列的基本原理是将需要执行的任务按顺序排列在队列中,并提供一组工作线程或者工作进程来处理队列中的任务。当有新的任务到达时,它们会被添加到队列的末尾,工作线程或工作进程从队列的头部获取任务,并执行相应的处理操作。
  工作队列和之前学习的 tasklet 有什么不同呢?tasklet 也是实现中断下半部分的机制之一。他们最主要的区别是 tasklet 不能休眠,而工作队列是可以休眠的,所以tasklet 可以用来处理比较耗时间的事情,而工作队列可以处理更耗时间的事情。
  工作队列将工作推后以后,会交给内核线程去执行。Linux 在启动过程中会创建一个工作者内核线程,这个线程创建以后处于 sleep 状态。当有工作需要处理的时候,会唤醒这个线程去处理工作。
  在内核中,工作队列包括共享工作队列和自定义工作队列这俩种类型。这两种类型的工作队列具有不同的特点和用途。
  1 共享队列是由内核管理的全局工作队列,用于处理内核中一些系统级任务。共享工作队列是内核中一个默认工作队列,可以由多个内核组件和驱动程序共享使用。
  2 自定义工作队列是由内核或驱动程序创建的特定工作队列,用于处理特定的任务。自定义工作队列通常与特定的内核模块或驱动程序相关联,用于执行该模块或驱动程序相关的任务。

二、共享工作队列

  在 Linux 内核中,使用 work_struct 结构体表示一个工作项,这些工作组织成工作队列,工作队列使用 workqueue_struct 结构体表示。work_struct 结构体表示一个工作项,定义在 include/linux/workqueue.h 中,如下所示:

struct work_struct 
{
	atomic_long_t data;
	struct list_head entry;
	work_func_t func; /* 工作队列处理函数 */
};
typedef void (*work_func_t)(struct work_struct *work); //工作函数

三、 共享工作队列相关接口函数

3.1、初始化函数

  简单创建工作很简单,直接定义一个work_struct 结构体变量即可,然后使用 INIT_WORK 宏来初始化工作,INIT_WORK 宏定义如下:

#define INIT_WORK(_work,_func)

  INIT_WORK 宏接受两个参数:_work 和 _func,分别表示要初始化的工作项和工作项的处理函数。
  也可以使用 DECLARE_WORK 宏一次性完成工作的创建和初始化,宏定义如下

#define DECLARE_WORK(n, f)

  参数 n 表示定义的工作(work_struct),f 表示工作对应的处理函数。

3.2、调度/取消调度工作队列函数

  工作队列需要调度才能运行的,工作的调度函数为schedule_work,函数原型如下所示:

static inline bool schedule_work(struct work_struct *work)

  参数是指向工作项的指针。这个函数作用是将工作项提交到工作队列中,并请求调度器在合适的时机执行工作项。该函数会返回一个布尔值,表示工作项是否成功被提交到工作队列。
  如果想要取消该工作项的调度,使用以下函数:

bool cancel_work_sync(struct work_struct *work);

  参数是指向工作项的指针。这个函数的作用是取消该工作项的调度。如果工作项已经在工作队列中,它将被从队列中移除。如果工作项已经在工作队列中,它将被从队列中移除,并等待工作项执行完成。函数返回一个布尔值,表示工作项是否成功取消。

四、代码示例

4.1、驱动层程序

#include 
#include 
#include 
#include 
#include 
#include 

int irq;

struct work_struct test_workqueue;
// 工作项处理函数
void test_work(struct work_struct *work)
{
  msleep(1000);
  printk("This is test_work\n");
}
// 中断处理函数
irqreturn_t test_interrupt(int irq, void *args)
{
  printk("This is test_interrupt\n");
  // 提交工作项到工作队列
  schedule_work(&test_workqueue);
  return IRQ_RETVAL(IRQ_HANDLED);
}

static int interrupt_irq_init(void)
{
  int ret;
  irq = gpio_to_irq(101); // 将GPIO映射为中断号
  printk("irq is %d\n", irq);
  // 请求中断
  ret = request_irq(irq, test_interrupt, IRQF_TRIGGER_RISING, "test", NULL);
  if (ret < 0)
  {
    printk("request_irq is error\n");
    return -1;
  }
  // 初始化工作项
  INIT_WORK(&test_workqueue, test_work);
  return 0;
}

static void interrupt_irq_exit(void)
{
  free_irq(irq, NULL); // 释放中断
  printk("bye bye\n");
}

module_init(interrupt_irq_init);
module_exit(interrupt_irq_exit);

4.2、linux中断下文工作队列之共享工作队列使用API要点

struct work_struct test_workqueue;
 // 初始化工作项
  INIT_WORK(&test_workqueue, test_work);
  // 提交工作项到工作队列
  schedule_work(&test_workqueue);

你可能感兴趣的:(RK3568,linux驱动开发笔记(迅为),linux)