-
Notifications
You must be signed in to change notification settings - Fork 4
/
lexus.c
216 lines (176 loc) · 6.54 KB
/
lexus.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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/proc_fs.h>
#include <linux/slab.h>
#include <linux/timer.h>
#include <linux/spinlock.h>
#include <linux/sched.h>
#include <linux/kthread.h>
#include <linux/uaccess.h> /* for copy_to_user and copy_from_user */
#include <linux/random.h> /* for random number generator */
#include <linux/miscdevice.h> /* for misc devices */
#include <linux/pid.h> /* for pid_task */
#include "lexus.h"
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Jidong Xiao"); /* Note: change this line to your name! */
MODULE_DESCRIPTION("CS452 Lexus");
#define DEBUG 1 /* Note: uncomment this line so you can see debug messages in /var/log/messages, or when you run dmesg */
/* this integers tracks how many number of tickets we have in total */
unsigned long nTickets = 0;
/* this variable is the timer, which helps us to call your lexus_schedule() every 200 millisecond.
* you don't need to use this variable in the four functions you implement. */
static struct timer_list dispatch_timer;
/* each lexus_task_struct represents one process in the lottery scheduling system */
struct lexus_task_struct {
struct list_head list; /* Kernel's list structure */
struct task_struct* task;
unsigned long pid;
unsigned long tickets;
task_state state;
};
/* use this global variable to track all registered tasks, by adding into its list */
static struct lexus_task_struct lexus_task_struct;
/* the currently running lexus task */
static struct lexus_task_struct *lexus_current;
/* spinlock to protect the linked list, and the global variables defined in this kernel module */
static spinlock_t lexus_lock;
/* dispatch kernel thread */
static struct task_struct *dispatch_kthread;
/* given a pid, returns its task_struct */
struct task_struct* find_task_by_pid(unsigned int pid)
{
struct task_struct* task;
rcu_read_lock();
task=pid_task(find_vpid(pid), PIDTYPE_PID);
rcu_read_unlock();
return task;
}
/* free all the lexus_task_struct instances: delete its list,
* and free its memory allocated via kmalloc().
* this function is called in lexus_exit(), you won't use this function. */
void free_lexus_list(void) {
struct list_head *p, *n;
struct lexus_task_struct *tmp;
unsigned long flags;
spin_lock_irqsave(&lexus_lock, flags);
/* You can just treat this list_for_each_safe() as a for loop:
* for (p = lexus_task_struct.list->next; p != lexus_task_struct.list; p = p->next),
* you can ignore n, it's a temporary pointer used inside the loop. */
list_for_each_safe(p, n, &lexus_task_struct.list) {
tmp = list_entry(p, struct lexus_task_struct, list);
list_del(p);
kfree(tmp);
}
spin_unlock_irqrestore(&lexus_lock, flags);
}
/* register a process into the lottery scheduling system */
void lexus_register(struct lottery_struct lottery){
}
/* unregister a process from the lottery scheduling system */
void lexus_unregister(struct lottery_struct lottery){
}
/* executes a context switch: pick a task and dispatch it to the Linux CFS scheduler.
* note: the parameter data won't be used in this program. */
int lexus_schedule(void *data)
{
while(!kthread_should_stop()){
printk(KERN_ERR "hello scheduler\n");
// let the dispatch kthread sleep
set_current_state(TASK_INTERRUPTIBLE);
schedule();
}
return 0;
}
/* handle ioctl system calls.
* note: the parameter filp won't be used in this program. */
static long lexus_dev_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)
{
return 0;
}
/* gets called when the timer goes off, we then reset the timer so as to make sure
* this function gets called periodically - every 200 milliseconds. */
void dispatch_timer_callback(unsigned long data)
{
#ifdef DEBUG
printk("Timer\n" );
#endif
/* setup timer interval to 200 msecs */
mod_timer(&dispatch_timer, jiffies + msecs_to_jiffies(200));
if(nTickets == 0) // nTickets being zero suggests there is no registered processes.
return;
#ifdef DEBUG
printk("wake up dispatch kthread...\n" );
#endif
/* wake up the lottery scheduling kthread */
wake_up_process(dispatch_kthread);
}
static const struct file_operations lexus_chardev_ops = {
.owner = THIS_MODULE,
.unlocked_ioctl = lexus_dev_ioctl,
.compat_ioctl = lexus_dev_ioctl,
.llseek = noop_llseek,
};
/* once we call misc_reigster(lexus_dev), a file called /dev/lexus will be created.
* any ioctl commands sent to this device will be handled by lexus_dev.fops.unlocked_ioctl,
* which is lexus_dev_ioctl(). */
static struct miscdevice lexus_dev = {
.minor = LEXUS_MINOR,
.name = "lexus",
.fops = &lexus_chardev_ops,
.mode = 0666,
};
/* called when module is loaded */
int __init lexus_init(void)
{
int r;
#ifdef DEBUG
printk("<1> lexus: loading.\n");
#endif
/* creating the device file /dev/lexus */
r = misc_register(&lexus_dev);
if (r) {
printk(KERN_ERR "lexus: misc device register failed\n");
return r;
}
/* the lexus version of "current" - in Linux kernel, the global variable "current" points to the currently running process - its task_struct */
lexus_current = NULL;
/* initialize the list_head to be empty */
INIT_LIST_HEAD(&lexus_task_struct.list);
/* a kernel thread named lexus_dispatch will be running at the background, which calls lexus_schedule().
* We don't need to pass any parameter lexus_schedule(), thus here the 2nd parameter is NULL. */
dispatch_kthread = kthread_create(lexus_schedule, NULL, "lexus_dispatch");
/* initialize the spin lock */
spin_lock_init(&lexus_lock);
/* setup your timer to call dispatch_timer_callback */
setup_timer(&dispatch_timer, dispatch_timer_callback, 0);
/* setup timer interval to 200 msecs */
mod_timer(&dispatch_timer, jiffies + msecs_to_jiffies(200));
#ifdef DEBUG
printk("<1> lexus: loaded.\n");
#endif
return 0;
}
/* called when module is unloaded */
void __exit lexus_exit(void)
{
#ifdef DEBUG
printk("<1> lexus: unloading.\n");
#endif
/* now it's time to exit the dispatch kthread, we wake it up so that it runs and checks the stop flag at the beginning of the while loop */
wake_up_process(dispatch_kthread);
kthread_stop(dispatch_kthread);
/* remove kernel timer when unloading module */
del_timer(&dispatch_timer);
/* free the memory allocated for each lexus_task_struct */
free_lexus_list();
/* removing the device file /dev/lexus */
misc_deregister(&lexus_dev);
#ifdef DEBUG
printk("<1> lexus: unloaded.\n");
#endif
}
// register init and exit funtions
module_init(lexus_init);
module_exit(lexus_exit);
/* vim: set ts=4: */