Document directory
A work queue is a form of pushing and executing jobs. It is executed by a kernel thread in the process context and cannot access user space. The most important feature is that the work queue allows rescheduling or even sleep. The work queue subsystem provides a default worker thread to handle these jobs. The default worker thread is events/n. Here N is the number of the processor. Each processor corresponds to a thread and you can create a worker thread by yourself.
1. Definition of work
Typedef void (* work_func_t) (struct work_struct * work); initialize the processing function declare_work (n, F) in the definition; # define declare_work (n, F) struct work_struct n = _ work_initializer (n, f) # DEFINE _ work_initializer (n, f ){\. data = work_data_init (0 ),\. entry = {& (n ). entry, & (n ). entry },\. func = (f) \} first defined and then initialized the processing function struct work_struct init_work (struct work_struct * Work, func_t); # define init_work (_ work, _ FUNC) \ do {\__ init_work (_ work), (_ FUNC), 0); \} while (
Use declare_delayed_work definition and init_delayed_work initialization when using a function or macro with delay.
2. Use the shared queues provided by the kernel
Schedule the work, that is, submit the processing function of the given work to the default work queue and worker thread. Int schedule_work (struct work_struct * work); ensure that there is no queue entry to run anywhere in the system. Void flush_scheduled_work (void); delay in executing a task int round (struct delayed_struct * Work, unsigned long delay); Remove entries from a work queue; int round (struct delayed_struct * work );
Test example
Void myfunc (struct work_struct * ws); declare_work (mywork, myfunc); // define void myfunc (struct work_struct * ws) {printk (kern_alert "myfunc current-> PID % d \ n", current-> PID); ssleep (1 ); printk (kern_alert "myfunc current-> PID % d \ n", current-> PID); ssleep (1 ); printk (kern_alert "myfunc current-> PID % d \ n", current-> PID); ssleep (1) ;}call schedule_work (& mywork) when loading the module ); printk (kern_alert "Main Current-> PID % d \ n", current-> PID );
Test Results
Output pidmain current-> PID 2883 myfunc current-> PID 4 myfunc current-> PID 4 myfunc current-> PID 4 [root @ fontlose module] # ps PID user vsz STAT command 1 root 2108 s init 2 root 0 SW [ksoftirqd/0] 3 root 0 SW [watchdog/0] 4 root 0 SW <[events/0]
Myfunc runs in a process whose PID is 4. Check that the process whose PID is 4 is events/0. Use the shared queues provided by the kernel to maintain the sequential execution, after a job is done, the next job will be implemented. If a job has time-consuming processing, such as blocking wait signals or locks, the subsequent work will not be executed. If you do not like queuing or are embarrassed to let others wait for too long, you can create your own worker thread, and all the work can be added to the work queue created by you, jobs in the queue run in the created worker thread.
3. Use custom queues
After the three macros are successfully created, the workqueue_struct * pointer is returned and the worker thread is created. The three macros differ in the singlethread and freezeable parameters. When singlethread is set to 0, a worker thread is created for each CPU, when the value is 1, only one worker thread is created on the currently running CPU. Freezeable will affect the pf_nofreeze mark of the kernel thread structure thread_info
if (!cwq->freezeable) current->flags |= PF_NOFREEZE; set_user_nice(current, -5);
The test points set in the thread function are as follows:
if (cwq->freezeable) try_to_freeze();
If the flag pf_nofreeze is set, the process will not be suspended when the system is suspended.
Main functions
# Define create_workqueue (name) _ create_workqueue (name), 0, 0) // a worker thread is created for each CPU during multi-processor process # define create_freezeable_workqueue (name) _ create_workqueue (name), 1, 1) // create only one worker thread. If the system hangs, the thread also hangs. # define create_singlethread_workqueue (name) _ create_workqueue (name ), 1, 0) // create only one worker thread, system suspension means that the thread does not suspend the preceding three macro calls _ create_workqueue Function Definition extern struct workqueue_struct * _ create_workqueue (const char * Name, int singlethread , Int freezeable); releases the created Job Queue resource void destroy_workqueue (struct workqueue_struct * WQ) to call the Job Queue (struct workqueue_struct * WQ, struct delay_struct * Work, unsigned long delay) cancel the delayed work of the specified job queue cancel_delayed_work (struct delay_struct * Work) add work to the Job Queue for scheduling queue_work (struct workqueue_struct * WQ, struct work_struct * Work) wait until all tasks in the queue are completed. Void flush_workqueue (struct workqueue_struct * WQ );
Main test code
Void myfunc (struct work_struct * ws); struct workqueue_struct * wqueue; declare_work (mywork, myfunc); void myfunc (struct work_struct * ws) {printk (kern_alert "myfunc 1 Current-> PID % d \ n", current-> PID); ssleep (1 ); printk (kern_alert "myfunc 2 Current-> PID % d \ n", current-> PID); ssleep (1 ); printk (kern_alert "myfunc 3 Current-> PID % d \ n", current-> PID); ssleep (1 );} run wqueue = create_workqueue ("myqueue"); queue_work (wqueue, & mywork); printk (kern_alert "Main Current-> PID % d \ n ", current-> PID );
Test Results
main current->pid 1010 myfunc 1 current->pid 1016 myfunc 2 current->pid 1016 myfunc 3 current->pid 1016 ps....1016 root 0 SW< [myqueue/0]
It can be seen that the function runs in a process with a PID of 1016, PS view the process name myqueue/0.