aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--kernel/kthread.c69
1 files changed, 28 insertions, 41 deletions
diff --git a/kernel/kthread.c b/kernel/kthread.c
index bc5d1f0b25a4..9b1a7de26979 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -35,17 +35,13 @@ struct kthread_create_info
35 struct list_head list; 35 struct list_head list;
36}; 36};
37 37
38struct kthread_stop_info 38struct kthread {
39{ 39 int should_stop;
40 struct task_struct *k; 40 struct completion exited;
41 int err;
42 struct completion done;
43}; 41};
44 42
45/* Thread stopping is done by setthing this var: lock serializes 43#define to_kthread(tsk) \
46 * multiple kthread_stop calls. */ 44 container_of((tsk)->vfork_done, struct kthread, exited)
47static DEFINE_MUTEX(kthread_stop_lock);
48static struct kthread_stop_info kthread_stop_info;
49 45
50/** 46/**
51 * kthread_should_stop - should this kthread return now? 47 * kthread_should_stop - should this kthread return now?
@@ -56,20 +52,22 @@ static struct kthread_stop_info kthread_stop_info;
56 */ 52 */
57int kthread_should_stop(void) 53int kthread_should_stop(void)
58{ 54{
59 return (kthread_stop_info.k == current); 55 return to_kthread(current)->should_stop;
60} 56}
61EXPORT_SYMBOL(kthread_should_stop); 57EXPORT_SYMBOL(kthread_should_stop);
62 58
63static int kthread(void *_create) 59static int kthread(void *_create)
64{ 60{
61 /* Copy data: it's on kthread's stack */
65 struct kthread_create_info *create = _create; 62 struct kthread_create_info *create = _create;
66 int (*threadfn)(void *data); 63 int (*threadfn)(void *data) = create->threadfn;
67 void *data; 64 void *data = create->data;
68 int ret = -EINTR; 65 struct kthread self;
66 int ret;
69 67
70 /* Copy data: it's on kthread's stack */ 68 self.should_stop = 0;
71 threadfn = create->threadfn; 69 init_completion(&self.exited);
72 data = create->data; 70 current->vfork_done = &self.exited;
73 71
74 /* OK, tell user we're spawned, wait for stop or wakeup */ 72 /* OK, tell user we're spawned, wait for stop or wakeup */
75 __set_current_state(TASK_UNINTERRUPTIBLE); 73 __set_current_state(TASK_UNINTERRUPTIBLE);
@@ -77,15 +75,12 @@ static int kthread(void *_create)
77 complete(&create->done); 75 complete(&create->done);
78 schedule(); 76 schedule();
79 77
80 if (!kthread_should_stop()) 78 ret = -EINTR;
79 if (!self.should_stop)
81 ret = threadfn(data); 80 ret = threadfn(data);
82 81
83 /* It might have exited on its own, w/o kthread_stop. Check. */ 82 /* we can't just return, we must preserve "self" on stack */
84 if (kthread_should_stop()) { 83 do_exit(ret);
85 kthread_stop_info.err = ret;
86 complete(&kthread_stop_info.done);
87 }
88 return 0;
89} 84}
90 85
91static void create_kthread(struct kthread_create_info *create) 86static void create_kthread(struct kthread_create_info *create)
@@ -195,30 +190,22 @@ EXPORT_SYMBOL(kthread_bind);
195 */ 190 */
196int kthread_stop(struct task_struct *k) 191int kthread_stop(struct task_struct *k)
197{ 192{
193 struct kthread *kthread;
198 int ret; 194 int ret;
199 195
200 mutex_lock(&kthread_stop_lock);
201
202 /* It could exit after stop_info.k set, but before wake_up_process. */
203 get_task_struct(k);
204
205 trace_sched_kthread_stop(k); 196 trace_sched_kthread_stop(k);
197 get_task_struct(k);
206 198
207 /* Must init completion *before* thread sees kthread_stop_info.k */ 199 kthread = to_kthread(k);
208 init_completion(&kthread_stop_info.done); 200 barrier(); /* it might have exited */
209 smp_wmb(); 201 if (k->vfork_done != NULL) {
202 kthread->should_stop = 1;
203 wake_up_process(k);
204 wait_for_completion(&kthread->exited);
205 }
206 ret = k->exit_code;
210 207
211 /* Now set kthread_should_stop() to true, and wake it up. */
212 kthread_stop_info.k = k;
213 wake_up_process(k);
214 put_task_struct(k); 208 put_task_struct(k);
215
216 /* Once it dies, reset stop ptr, gather result and we're done. */
217 wait_for_completion(&kthread_stop_info.done);
218 kthread_stop_info.k = NULL;
219 ret = kthread_stop_info.err;
220 mutex_unlock(&kthread_stop_lock);
221
222 trace_sched_kthread_stop_ret(ret); 209 trace_sched_kthread_stop_ret(ret);
223 210
224 return ret; 211 return ret;