2023.7.16 linux 软中断Softirqs 队列 Workqueues 并发管理队列cmwq

发布时间 2023-07-16 23:07:02作者: 杨大茄子

Implementing work-deferring mechanisms     延期任务

Softirqs: Executed in an atomic context       # kernel/softirq.c  ;  <linux/interrupt.h>.

Tasklets: Executed in an atomic context 

Workqueues: Executed in a process context

 

struct softirq_action { void (*action)(struct softirq_action *); };

void softirq_handler(struct softirq_action *h)

void open_softirq(int nr, void (*action)(struct softirq_action *))

nr represents the softirq index, which is also considered as the softirq priority (where 0 is the highest). action is a pointer to the softirq handler. Possible indexes are enumerated in the following code snippet:

enum {

  HI_SOFTIRQ=0, /* High-priority tasklets */

  TIMER_SOFTIRQ, /* Timers */

  NET_TX_SOFTIRQ, /* Send network packets */

  NET_RX_SOFTIRQ, /* Receive network packets */

  BLOCK_SOFTIRQ, /* Block devices */  

  BLOCK_IOPOLL_SOFTIRQ, /* Block devices with I/O polling * blocked on other CPUs */

  TASKLET_SOFTIRQ,/* Normal Priority tasklets */ SCHED_SOFTIRQ, /* Scheduler */

  HRTIMER_SOFTIRQ,/* High-resolution timers */

  RCU_SOFTIRQ, /* RCU locking */

  NR_SOFTIRQS /* This only represent the number * of softirqs type, 10 actually */

};    #nr数值越小,优先级越大

const char * const softirq_to_name[NR_SOFTIRQS] = { "HI", "TIMER", "NET_TX", "NET_RX", "BLOCK", "BLOCK_IOPOLL", "TASKLET", "SCHED", "HRTIMER", "RCU" };

cat /proc/softirqs

void __raise_softirq_irqoff(unsigned int nr)

void raise_softirq_irqoff(unsigned int nr)

void raise_softirq(unsigned int nr)

 

Tasklets

void tasklet_setup(struct tasklet_struct *t, void (*callback)(struct tasklet_struct *));    deprecated

 

Workqueues

  Worker threads, which are dedicated threads that execute and pull the functions off the queue, one by one, one after the other. 

   Worker pools: This is a collection of worker threads (a thread pool) that are used to better manage the worker threads.

linux/workqueue.h

DECLARE_WORK(name, function)    #静态初始化一个work

DECLARE_DELAYED_WORK(name, function)    #初始化一个延迟work

INIT_WORK(work, func );      #动态

INIT_DELAYED_WORK( work, func);

struct work_struct { atomic_long_t data; struct list_head entry; work_func_t func; };

struct delayed_work { struct work_struct work; struct timer_list timer; struct workqueue_struct *wq; int cpu; };

typedef void (*work_func_t)(struct work_struct *work);

struct delayed_work *to_delayed_work( struct work_struct *work)

struct workqueue_struct *create_workqueue(const char *name)    #为每一个cpu创建一个专门的线程

struct workqueue_struct *create_singlethread_workqueue( const char *name)

bool queue_work(struct workqueue_struct *wq, struct work_struct *work)    #排班work

bool queue_delayed_work(struct workqueue_struct *wq, struct delayed_work *dwork, unsigned long delay)    #排延迟工作

取消work

bool cancel_work_sync(struct work_struct *work)

bool cancel_delayed_work(struct delayed_work *dwork)

bool cancel_delayed_work_sync(struct delayed_work *dwork)

void flush_workqueue(struct worksqueue_struct * queue);

void destroy_workqueue(structure workqueque_struct *queue);    #摧毁工作队列

Kernel-global workqueue – the shared queue    #在内核初始化时已经创建

 int schedule_work(struct work_struct *work);

int schedule_delayed_work(struct delayed_work *dwork, unsigned long delay);

int schedule_work_on(int cpu, struct work_struct *work);    #指定cpu排班任务

int schedule_delayed_work_on(int cpu, struct delayed_work *dwork, unsigned long delay);

void flush_scheduled_work(void);

Concurrency Managed Workqueue (cmwq),

struct workqueue_struct *alloc_workqueue(const char *fmt, unsigned int flags, int max_active, ...);

#define alloc_ordered_workqueue(fmt, flags, args...) [...]    #processes each work item one by one in queued order (that is, first-in, first-out (FIFO) order).

void destroy_workqueue(struct workqueue_struct *wq)

flags:

WQ_UNBOUND 不绑定cpu 由系统自己分配

WQ_MEM_RECLAIM  可以内存救援

WQ_FREEZABLE    省电,随系统休眠而休眠

WQ_HIGHPRI    高优先级,保证立即执行

WQ_CPU_INTENSIVE  表明cpu集约型任务 会被其他任务delay

queue_work_on()  可以指定cpu

 

Note that schedule_work() is a wrapper that calls queue_work() on the system workqueue (system_wq), while schedule_work_on() is a wrapper around queue_work_on(). Also, keep in mind the following: system_wq = alloc_workqueue("events", 0, 0);. You can have a look at the workqueue_init_early() function in kernel/ workqueue.c in kernel sources to see how other system-wide workqueues are created.