aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMaxim Levitsky <maximlevitsky@gmail.com>2010-09-06 17:26:06 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2010-10-21 05:54:12 -0400
commitc6ef1e7fdc752bbaeacb3570cf955ba2ad60c61b (patch)
tree0d9fa654950550b6bc1fd5d0c6f1681bdb084666
parentc47d3e7f94a88bbb4c2c441fb34d98a6db32cb8f (diff)
[media] IR: plug races in IR raw thread
Unfortunelly (my fault) the kernel thread that now handles IR processing has classical races in regard to wakeup and stop. This patch hopefully closes them all. Tested with module reload running in a loop, while receiver is blasted with IR data for 10 minutes. Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com> Acked-by: Jarod Wilson <jarod@redhat.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--drivers/media/IR/ir-core-priv.h2
-rw-r--r--drivers/media/IR/ir-raw-event.c34
2 files changed, 27 insertions, 9 deletions
diff --git a/drivers/media/IR/ir-core-priv.h b/drivers/media/IR/ir-core-priv.h
index 0ad8ea39b39e..90eb3912c455 100644
--- a/drivers/media/IR/ir-core-priv.h
+++ b/drivers/media/IR/ir-core-priv.h
@@ -17,6 +17,7 @@
17#define _IR_RAW_EVENT 17#define _IR_RAW_EVENT
18 18
19#include <linux/slab.h> 19#include <linux/slab.h>
20#include <linux/spinlock.h>
20#include <media/ir-core.h> 21#include <media/ir-core.h>
21 22
22struct ir_raw_handler { 23struct ir_raw_handler {
@@ -33,6 +34,7 @@ struct ir_raw_handler {
33struct ir_raw_event_ctrl { 34struct ir_raw_event_ctrl {
34 struct list_head list; /* to keep track of raw clients */ 35 struct list_head list; /* to keep track of raw clients */
35 struct task_struct *thread; 36 struct task_struct *thread;
37 spinlock_t lock;
36 struct kfifo kfifo; /* fifo for the pulse/space durations */ 38 struct kfifo kfifo; /* fifo for the pulse/space durations */
37 ktime_t last_event; /* when last event occurred */ 39 ktime_t last_event; /* when last event occurred */
38 enum raw_event_type last_type; /* last event type */ 40 enum raw_event_type last_type; /* last event type */
diff --git a/drivers/media/IR/ir-raw-event.c b/drivers/media/IR/ir-raw-event.c
index 8e0e1b1f8c87..119b567feeab 100644
--- a/drivers/media/IR/ir-raw-event.c
+++ b/drivers/media/IR/ir-raw-event.c
@@ -39,22 +39,34 @@ static int ir_raw_event_thread(void *data)
39 struct ir_raw_event ev; 39 struct ir_raw_event ev;
40 struct ir_raw_handler *handler; 40 struct ir_raw_handler *handler;
41 struct ir_raw_event_ctrl *raw = (struct ir_raw_event_ctrl *)data; 41 struct ir_raw_event_ctrl *raw = (struct ir_raw_event_ctrl *)data;
42 int retval;
42 43
43 while (!kthread_should_stop()) { 44 while (!kthread_should_stop()) {
44 try_to_freeze();
45 45
46 mutex_lock(&ir_raw_handler_lock); 46 spin_lock_irq(&raw->lock);
47 retval = kfifo_out(&raw->kfifo, &ev, sizeof(ev));
48
49 if (!retval) {
50 set_current_state(TASK_INTERRUPTIBLE);
47 51
48 while (kfifo_out(&raw->kfifo, &ev, sizeof(ev)) == sizeof(ev)) { 52 if (kthread_should_stop())
49 list_for_each_entry(handler, &ir_raw_handler_list, list) 53 set_current_state(TASK_RUNNING);
50 handler->decode(raw->input_dev, ev); 54
51 raw->prev_ev = ev; 55 spin_unlock_irq(&raw->lock);
56 schedule();
57 continue;
52 } 58 }
53 59
54 mutex_unlock(&ir_raw_handler_lock); 60 spin_unlock_irq(&raw->lock);
55 61
56 set_current_state(TASK_INTERRUPTIBLE); 62
57 schedule(); 63 BUG_ON(retval != sizeof(ev));
64
65 mutex_lock(&ir_raw_handler_lock);
66 list_for_each_entry(handler, &ir_raw_handler_list, list)
67 handler->decode(raw->input_dev, ev);
68 raw->prev_ev = ev;
69 mutex_unlock(&ir_raw_handler_lock);
58 } 70 }
59 71
60 return 0; 72 return 0;
@@ -232,11 +244,14 @@ EXPORT_SYMBOL_GPL(ir_raw_event_set_idle);
232void ir_raw_event_handle(struct input_dev *input_dev) 244void ir_raw_event_handle(struct input_dev *input_dev)
233{ 245{
234 struct ir_input_dev *ir = input_get_drvdata(input_dev); 246 struct ir_input_dev *ir = input_get_drvdata(input_dev);
247 unsigned long flags;
235 248
236 if (!ir->raw) 249 if (!ir->raw)
237 return; 250 return;
238 251
252 spin_lock_irqsave(&ir->raw->lock, flags);
239 wake_up_process(ir->raw->thread); 253 wake_up_process(ir->raw->thread);
254 spin_unlock_irqrestore(&ir->raw->lock, flags);
240} 255}
241EXPORT_SYMBOL_GPL(ir_raw_event_handle); 256EXPORT_SYMBOL_GPL(ir_raw_event_handle);
242 257
@@ -275,6 +290,7 @@ int ir_raw_event_register(struct input_dev *input_dev)
275 return rc; 290 return rc;
276 } 291 }
277 292
293 spin_lock_init(&ir->raw->lock);
278 ir->raw->thread = kthread_run(ir_raw_event_thread, ir->raw, 294 ir->raw->thread = kthread_run(ir_raw_event_thread, ir->raw,
279 "rc%u", (unsigned int)ir->devno); 295 "rc%u", (unsigned int)ir->devno);
280 296