1 #include <linux/version.h>
2 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17))
3 #include <linux/config.h>
6 #if defined(MODVERSIONS)
7 #include <linux/modversions.h>
9 #include <linux/kernel.h>
10 #include <linux/sched.h>
12 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,40))
13 #include <linux/tqueue.h>
15 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17))
16 #include <linux/devfs_fs_kernel.h>
20 #include <linux/wait.h>
21 #include <linux/signal.h>
22 #include <linux/interrupt.h>
24 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27))
25 #include <asm/semaphore.h>
27 #include <linux/semaphore.h>
30 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38))
31 #include <linux/smp_lock.h>
34 #include "../include/kthread.h"
36 /* private functions */
37 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,40))
38 static void kthread_launcher(void *data)
40 static void kthread_launcher(unsigned long data)
43 kthread_t *kthread = (kthread_t *)data;
45 kernel_thread((int (*)(void *))kthread->function, (void *)kthread, 0);
48 /* public functions */
50 /* create a new kernel thread. Called by the creator. */
51 void start_kthread(void (*func)(kthread_t *), kthread_t *kthread)
53 /* initialize the semaphore:
54 we start with the semaphore locked. The new kernel
55 thread will setup its stuff and unlock it. This
56 control flow (the one that creates the thread) blocks
57 in the down operation below until the thread has reached
60 sema_init(&kthread->startstop_sem, 0);
62 /* store the function to be executed in the data passed to
64 kthread->function=func;
66 /* create the new thread my running a task through keventd */
68 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,40))
70 /* initialize the task queue structure */
72 INIT_LIST_HEAD(&kthread->tq.list);
73 kthread->tq.routine = kthread_launcher;
74 kthread->tq.data = kthread;
76 /* and schedule it for execution */
77 schedule_task(&kthread->tq);
79 /* initialize tasklet */
80 tasklet_init(&kthread->tq, kthread_launcher, (unsigned long)kthread);
81 /* and schedule it for execution */
82 tasklet_schedule(&kthread->tq);
85 /* wait till it has reached the setup_thread routine */
86 down(&kthread->startstop_sem);
89 /* stop a kernel thread. Called by the removing instance */
90 void stop_kthread(kthread_t *kthread)
92 if (kthread->thread == NULL)
94 printk("stop_kthread: killing non existing thread!\n");
98 /* this function needs to be protected with the big
99 kernel lock (lock_kernel()). The lock must be
100 grabbed before changing the terminate
101 flag and released after the down() call. */
104 /* initialize the semaphore. We lock it here, the
105 leave_thread call of the thread to be terminated
106 will unlock it. As soon as we see the semaphore
107 unlocked, we know that the thread has exited.
109 sema_init(&kthread->startstop_sem,0);
111 /* We need to do a memory barrier here to be sure that
112 the flags are visible on all CPUs.
116 /* set flag to request thread termination */
117 kthread->terminate = 1;
119 /* We need to do a memory barrier here to be sure that
120 the flags are visible on all CPUs.
123 #warning The local code for kernel thread support is not more needed for recent 2.6 kernels
124 #warning and code should be modified to emulate same interface for older kernels
125 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20))
126 kill_proc(kthread->thread->pid, SIGKILL, 1);
127 #else /* >= 2,6,20 */
128 send_sig(SIGKILL, kthread->thread, 1);
129 #endif /* >= 2,6,20 */
131 /* block till thread terminated */
132 down(&kthread->startstop_sem);
134 /* release the big kernel lock */
137 /* now we are sure the thread is in zombie state. We
138 notify keventd to clean the process up.
140 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20))
141 kill_proc(2, SIGCHLD, 1);
142 #endif /* >= 2,6,20 */
146 /* initialize new created thread. Called by the new thread. */
147 void init_kthread(kthread_t *kthread, char *name)
149 /* fill in thread structure */
150 kthread->thread = current;
152 /* initialise termination flag */
153 kthread->terminate = 0;
155 /* initialise wait queue */
156 init_waitqueue_head(&kthread->queue);
158 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,40))
159 /* lock the kernel. A new kernel thread starts without
160 the big kernel lock, regardless of the lock state
161 of the creator (the lock level is *not* inheritated)
166 /* set signal mask to what we want to respond */
167 siginitsetinv(¤t->blocked, sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM));
169 /* set name of this process (max 15 chars + 0 !) */
170 sprintf(current->comm, name);
179 /* tell the creator that we are ready and let him continue */
180 up(&kthread->startstop_sem);
183 /* cleanup of thread. Called by the exiting thread. */
184 void exit_kthread(kthread_t *kthread)
186 /* we are terminating */
188 /* lock the kernel, the exit will unlock it */
190 kthread->thread = NULL;
193 /* notify the stop_kthread() routine that we are terminating. */
194 up(&kthread->startstop_sem);
195 /* the kernel_thread that called clone() does a do_exit here. */
197 /* there is no race here between execution of the "killer" and real termination
198 of the thread (race window between up and do_exit), since both the
199 thread and the "killer" function are running with the kernel lock held.
200 The kernel lock will be freed after the thread exited, so the code
201 is really not executed anymore as soon as the unload functions gets
202 the kernel lock back.
203 The init process may not have made the cleanup of the process here,
204 but the cleanup can be done safely with the module unloaded.