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