]> rtime.felk.cvut.cz Git - lincan.git/blob - lincan/src/kthread.c
2d387d310841236948969324a83c11c98a1e0c64
[lincan.git] / lincan / src / kthread.c
1 #include <linux/version.h>
2 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17))
3 #include <linux/config.h>
4 #endif
5
6 #if defined(MODVERSIONS)
7 #include <linux/modversions.h>
8 #endif
9 #include <linux/kernel.h>
10 #include <linux/sched.h>
11
12 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,40))
13   #include <linux/tqueue.h>
14 #else
15   #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17))
16     #include <linux/devfs_fs_kernel.h>
17   #endif
18 #endif
19
20 #include <linux/wait.h>
21 #include <linux/signal.h>
22 #include <linux/interrupt.h>
23
24
25 #include <asm/semaphore.h>
26 #include <linux/smp_lock.h>
27
28 #include "../include/kthread.h"
29
30 /* private functions */
31 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,40))
32 static void kthread_launcher(void *data)
33 #else
34 static void kthread_launcher(unsigned long data)
35 #endif
36 {
37   kthread_t *kthread = (kthread_t *)data;
38
39   kernel_thread((int (*)(void *))kthread->function, (void *)kthread, 0);
40 }
41
42 /* public functions */
43
44 /* create a new kernel thread. Called by the creator. */
45 void start_kthread(void (*func)(kthread_t *), kthread_t *kthread)
46 {
47     /* initialize the semaphore:
48        we start with the semaphore locked. The new kernel
49        thread will setup its stuff and unlock it. This
50        control flow (the one that creates the thread) blocks
51        in the down operation below until the thread has reached
52        the up() operation.
53     */
54     sema_init(&kthread->startstop_sem, 0);
55
56     /* store the function to be executed in the data passed to
57        the launcher */
58     kthread->function=func;
59
60     /* create the new thread my running a task through keventd */
61
62 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,40))
63
64     /* initialize the task queue structure */
65     kthread->tq.sync = 0;
66     INIT_LIST_HEAD(&kthread->tq.list);
67     kthread->tq.routine = kthread_launcher;
68     kthread->tq.data = kthread;
69
70     /* and schedule it for execution */
71     schedule_task(&kthread->tq);
72 #else
73     /* initialize tasklet */
74     tasklet_init(&kthread->tq, kthread_launcher, (unsigned long)kthread);
75     /* and schedule it for execution */
76     tasklet_schedule(&kthread->tq);
77 #endif
78
79     /* wait till it has reached the setup_thread routine */
80     down(&kthread->startstop_sem);
81 }
82
83 /* stop a kernel thread. Called by the removing instance */
84 void stop_kthread(kthread_t *kthread)
85 {
86     if (kthread->thread == NULL)
87     {
88         printk("stop_kthread: killing non existing thread!\n");
89         return;
90     }
91
92     /* this function needs to be protected with the big
93     kernel lock (lock_kernel()). The lock must be
94        grabbed before changing the terminate
95     flag and released after the down() call. */
96     lock_kernel();
97
98     /* initialize the semaphore. We lock it here, the
99        leave_thread call of the thread to be terminated
100        will unlock it. As soon as we see the semaphore
101        unlocked, we know that the thread has exited.
102     */
103     sema_init(&kthread->startstop_sem,0);
104
105     /* We need to do a memory barrier here to be sure that
106        the flags are visible on all CPUs.
107     */
108     mb();
109
110     /* set flag to request thread termination */
111     kthread->terminate = 1;
112
113     /* We need to do a memory barrier here to be sure that
114        the flags are visible on all CPUs.
115     */
116     mb();
117     kill_proc(kthread->thread->pid, SIGKILL, 1);
118
119     /* block till thread terminated */
120     down(&kthread->startstop_sem);
121
122     /* release the big kernel lock */
123     unlock_kernel();
124
125     /* now we are sure the thread is in zombie state. We
126        notify keventd to clean the process up.
127     */
128     kill_proc(2, SIGCHLD, 1);
129
130 }
131
132 /* initialize new created thread. Called by the new thread. */
133 void init_kthread(kthread_t *kthread, char *name)
134 {
135     /* fill in thread structure */
136     kthread->thread = current;
137
138     /* initialise termination flag */
139     kthread->terminate = 0;
140
141     /* initialise wait queue */
142     init_waitqueue_head(&kthread->queue);
143
144 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,40))
145     /* lock the kernel. A new kernel thread starts without
146       the big kernel lock, regardless of the lock state
147       of the creator (the lock level is *not* inheritated)
148     */
149     lock_kernel();
150 /*    daemonize(); */
151
152     /* set signal mask to what we want to respond */
153     siginitsetinv(&current->blocked, sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM));
154
155     /* set name of this process (max 15 chars + 0 !) */
156     sprintf(current->comm, name);
157
158     /* let others run */
159     unlock_kernel();
160 #else
161
162     daemonize(name);
163 #endif
164
165     /* tell the creator that we are ready and let him continue */
166     up(&kthread->startstop_sem);
167 }
168
169 /* cleanup of thread. Called by the exiting thread. */
170 void exit_kthread(kthread_t *kthread)
171 {
172     /* we are terminating */
173
174     /* lock the kernel, the exit will unlock it */
175     lock_kernel();
176     kthread->thread = NULL;
177     mb();
178
179     /* notify the stop_kthread() routine that we are terminating. */
180     up(&kthread->startstop_sem);
181     /* the kernel_thread that called clone() does a do_exit here. */
182
183     /* there is no race here between execution of the "killer" and real termination
184        of the thread (race window between up and do_exit), since both the
185        thread and the "killer" function are running with the kernel lock held.
186        The kernel lock will be freed after the thread exited, so the code
187        is really not executed anymore as soon as the unload functions gets
188        the kernel lock back.
189        The init process may not have made the cleanup of the process here,
190        but the cleanup can be done safely with the module unloaded.
191     */
192
193 }
194