aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2009-12-11 06:51:05 -0500
committerTakashi Iwai <tiwai@suse.de>2009-12-11 06:53:27 -0500
commitfcfdebe70759c74e2e701f69aaa7f0e5e32cf5a6 (patch)
tree4f31584d288d37d9168544bfe34d81cc4a8eef2f /sound
parent5f60e496083efb01893a899b6885828330db971f (diff)
ALSA: hrtimer - Fix lock-up
The timer stop callback can be called from snd_timer_interrupt(), which is called from the hrtimer callback. Since hrtimer_cancel() waits for the callback completion, this eventually results in a lock-up. This patch fixes the problem by just toggling a flag at stop callback and call hrtimer_cancel() later. Reported-and-tested-by: Wojtek Zabolotny <W.Zabolotny@elka.pw.edu.pl> Cc: <stable@kernel.org> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound')
-rw-r--r--sound/core/hrtimer.c15
1 files changed, 13 insertions, 2 deletions
diff --git a/sound/core/hrtimer.c b/sound/core/hrtimer.c
index 34c7d48f5061..7f4d744ae40a 100644
--- a/sound/core/hrtimer.c
+++ b/sound/core/hrtimer.c
@@ -37,14 +37,22 @@ static unsigned int resolution;
37struct snd_hrtimer { 37struct snd_hrtimer {
38 struct snd_timer *timer; 38 struct snd_timer *timer;
39 struct hrtimer hrt; 39 struct hrtimer hrt;
40 atomic_t running;
40}; 41};
41 42
42static enum hrtimer_restart snd_hrtimer_callback(struct hrtimer *hrt) 43static enum hrtimer_restart snd_hrtimer_callback(struct hrtimer *hrt)
43{ 44{
44 struct snd_hrtimer *stime = container_of(hrt, struct snd_hrtimer, hrt); 45 struct snd_hrtimer *stime = container_of(hrt, struct snd_hrtimer, hrt);
45 struct snd_timer *t = stime->timer; 46 struct snd_timer *t = stime->timer;
47
48 if (!atomic_read(&stime->running))
49 return HRTIMER_NORESTART;
50
46 hrtimer_forward_now(hrt, ns_to_ktime(t->sticks * resolution)); 51 hrtimer_forward_now(hrt, ns_to_ktime(t->sticks * resolution));
47 snd_timer_interrupt(stime->timer, t->sticks); 52 snd_timer_interrupt(stime->timer, t->sticks);
53
54 if (!atomic_read(&stime->running))
55 return HRTIMER_NORESTART;
48 return HRTIMER_RESTART; 56 return HRTIMER_RESTART;
49} 57}
50 58
@@ -58,6 +66,7 @@ static int snd_hrtimer_open(struct snd_timer *t)
58 hrtimer_init(&stime->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL); 66 hrtimer_init(&stime->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
59 stime->timer = t; 67 stime->timer = t;
60 stime->hrt.function = snd_hrtimer_callback; 68 stime->hrt.function = snd_hrtimer_callback;
69 atomic_set(&stime->running, 0);
61 t->private_data = stime; 70 t->private_data = stime;
62 return 0; 71 return 0;
63} 72}
@@ -78,16 +87,18 @@ static int snd_hrtimer_start(struct snd_timer *t)
78{ 87{
79 struct snd_hrtimer *stime = t->private_data; 88 struct snd_hrtimer *stime = t->private_data;
80 89
90 atomic_set(&stime->running, 0);
91 hrtimer_cancel(&stime->hrt);
81 hrtimer_start(&stime->hrt, ns_to_ktime(t->sticks * resolution), 92 hrtimer_start(&stime->hrt, ns_to_ktime(t->sticks * resolution),
82 HRTIMER_MODE_REL); 93 HRTIMER_MODE_REL);
94 atomic_set(&stime->running, 1);
83 return 0; 95 return 0;
84} 96}
85 97
86static int snd_hrtimer_stop(struct snd_timer *t) 98static int snd_hrtimer_stop(struct snd_timer *t)
87{ 99{
88 struct snd_hrtimer *stime = t->private_data; 100 struct snd_hrtimer *stime = t->private_data;
89 101 atomic_set(&stime->running, 0);
90 hrtimer_cancel(&stime->hrt);
91 return 0; 102 return 0;
92} 103}
93 104