]> rtime.felk.cvut.cz Git - lincan.git/blob - lincan/src/kthread.c
Adjust LinCAN sources to compile for 3.x Linux kernel.
[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 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38))
31   #include <linux/smp_lock.h>
32 #endif
33
34 #include "../include/kthread.h"
35
36 /* private functions */
37 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,40))
38 static void kthread_launcher(void *data)
39 #else
40 static void kthread_launcher(unsigned long data)
41 #endif
42 {
43   kthread_t *kthread = (kthread_t *)data;
44
45   kernel_thread((int (*)(void *))kthread->function, (void *)kthread, 0);
46 }
47
48 /* public functions */
49
50 /* create a new kernel thread. Called by the creator. */
51 void start_kthread(void (*func)(kthread_t *), kthread_t *kthread)
52 {
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
58        the up() operation.
59     */
60     sema_init(&kthread->startstop_sem, 0);
61
62     /* store the function to be executed in the data passed to
63        the launcher */
64     kthread->function=func;
65
66     /* create the new thread my running a task through keventd */
67
68 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,40))
69
70     /* initialize the task queue structure */
71     kthread->tq.sync = 0;
72     INIT_LIST_HEAD(&kthread->tq.list);
73     kthread->tq.routine = kthread_launcher;
74     kthread->tq.data = kthread;
75
76     /* and schedule it for execution */
77     schedule_task(&kthread->tq);
78 #else
79     /* initialize tasklet */
80     tasklet_init(&kthread->tq, kthread_launcher, (unsigned long)kthread);
81     /* and schedule it for execution */
82     tasklet_schedule(&kthread->tq);
83 #endif
84
85     /* wait till it has reached the setup_thread routine */
86     down(&kthread->startstop_sem);
87 }
88
89 /* stop a kernel thread. Called by the removing instance */
90 void stop_kthread(kthread_t *kthread)
91 {
92     if (kthread->thread == NULL)
93     {
94         printk("stop_kthread: killing non existing thread!\n");
95         return;
96     }
97
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. */
102     lock_kernel();
103
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.
108     */
109     sema_init(&kthread->startstop_sem,0);
110
111     /* We need to do a memory barrier here to be sure that
112        the flags are visible on all CPUs.
113     */
114     mb();
115
116     /* set flag to request thread termination */
117     kthread->terminate = 1;
118
119     /* We need to do a memory barrier here to be sure that
120        the flags are visible on all CPUs.
121     */
122     mb();
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 */
130
131     /* block till thread terminated */
132     down(&kthread->startstop_sem);
133
134     /* release the big kernel lock */
135     unlock_kernel();
136
137     /* now we are sure the thread is in zombie state. We
138        notify keventd to clean the process up.
139     */
140 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20))
141     kill_proc(2, SIGCHLD, 1);
142 #endif /* >= 2,6,20 */
143
144 }
145
146 /* initialize new created thread. Called by the new thread. */
147 void init_kthread(kthread_t *kthread, char *name)
148 {
149     /* fill in thread structure */
150     kthread->thread = current;
151
152     /* initialise termination flag */
153     kthread->terminate = 0;
154
155     /* initialise wait queue */
156     init_waitqueue_head(&kthread->queue);
157
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)
162     */
163     lock_kernel();
164 /*    daemonize(); */
165
166     /* set signal mask to what we want to respond */
167     siginitsetinv(&current->blocked, sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM));
168
169     /* set name of this process (max 15 chars + 0 !) */
170     sprintf(current->comm, name);
171
172     /* let others run */
173     unlock_kernel();
174 #else
175
176     daemonize(name);
177 #endif
178
179     /* tell the creator that we are ready and let him continue */
180     up(&kthread->startstop_sem);
181 }
182
183 /* cleanup of thread. Called by the exiting thread. */
184 void exit_kthread(kthread_t *kthread)
185 {
186     /* we are terminating */
187
188     /* lock the kernel, the exit will unlock it */
189     lock_kernel();
190     kthread->thread = NULL;
191     mb();
192
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. */
196
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.
205     */
206
207 }
208