-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathjob_list.c
140 lines (113 loc) · 3.28 KB
/
job_list.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#ifndef __KERNEL__
# define __KERNEL__
#endif
#ifndef MODULE
# define MODULE
#endif
/*
* Copyright (C) 2016 Fernando Vanyo Garcia
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Fernando Vanyo Garcia <[email protected]>
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/syscalls.h>
#include <linux/kthread.h>
#include <linux/slab.h>
#define AUTHOR "Fernando Vanyo <[email protected]>"
#define DESC "Simple Job queue for a unique kernel thread"
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR(AUTHOR);
MODULE_DESCRIPTION(DESC);
#define CHECK_EXIT \
do{ \
set_current_state(TASK_INTERRUPTIBLE); \
if (kthread_should_stop()){ \
break; \
} \
}while(0)
// List of Jobs for the worker thread //
typedef struct job_t {
void* (*func)(void* args);
void* args;
struct list_head list;
} job_t;
struct task_struct *task; // the worker kthread
job_t jobs;
void generic_job(void);
static int main_thread(void *data){
void* (*func_ptr)(void* arg);
void* args;
job_t *job_ptr;
while(!kthread_should_stop()){
//do work
if(!list_empty(&jobs.list)){
CHECK_EXIT;
printk(KERN_DEBUG "[kernel thread] Oh... I have job! :)\n");
// Get a job
job_ptr = list_first_entry_or_null(&jobs.list, struct job_t, list);
if (job_ptr != NULL){
printk(KERN_DEBUG "[kernel thread] doing the job....\n");
func_ptr = job_ptr->func;
args = job_ptr->args;
func_ptr(args);
// Free the node
list_del(&job_ptr->list);
kfree(job_ptr);
}
}
else{
//printk(KERN_DEBUG "[kernel thread] List empty....\n");
// Wait 500 ms //
CHECK_EXIT;
schedule_timeout(0.5 * HZ);
}
}
printk(KERN_DEBUG "[kernel thread] bye!!\n");
return 0;
}
void generic_job(){
printk(KERN_INFO "This is the generic job! I am %s\n", current->comm);
return;
}
static int __init entry_point(void) {
job_t *job_ptr;
INIT_LIST_HEAD(&jobs.list);
task = kthread_create(&main_thread, NULL, "MyKernelThread");
wake_up_process(task);
// wait 2 seconds
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(2 * HZ); //Wait 2 seconds
// add a job to the queue
printk(KERN_DEBUG "[%s] OK. 2 seconds later, I add a job to the queue\n", current->comm);
job_ptr = (job_t *) kmalloc(sizeof(struct job_t), GFP_KERNEL);
if(job_ptr != NULL){
job_ptr->func = (void*)generic_job;
job_ptr->args = NULL;
}
// else -> error in kmalloc :S
list_add_tail(&job_ptr->list, &jobs.list);
return 0;
}
static void __exit exit_point(void) {
printk(KERN_DEBUG "[%s] bye!!\n", current->comm);
kthread_stop(task);
return;
}
module_init(entry_point);
module_exit(exit_point);