Skip to content

Commit

Permalink
ALSA: timer: Replace tasklet with work
Browse files Browse the repository at this point in the history
The tasklet is an old API that should be deprecated, usually can be
converted to another decent API.  In ALSA core timer API, the
callbacks can be offlined to a tasklet when a flag is set in the timer
backend.  It can be achieved gracefully with a work queued in the
high-prio system workqueue.

This patch replaces the usage of tasklet in ALSA timer API with a
simple work.  Currently the tasklet feature is used only in the system
timer and hrtimer backends, so both are patched to use the new flag
name SNDRV_TIMER_HW_WORK, too.

Link: https://lore.kernel.org/r/[email protected]
Signed-off-by: Takashi Iwai <[email protected]>
  • Loading branch information
tiwai committed Sep 9, 2020
1 parent 68f86a9 commit bf08359
Show file tree
Hide file tree
Showing 3 changed files with 15 additions and 15 deletions.
8 changes: 4 additions & 4 deletions include/sound/timer.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@
#define SNDRV_TIMER_HW_STOP 0x00000002 /* call stop before start */
#define SNDRV_TIMER_HW_SLAVE 0x00000004 /* only slave timer (variable resolution) */
#define SNDRV_TIMER_HW_FIRST 0x00000008 /* first tick can be incomplete */
#define SNDRV_TIMER_HW_TASKLET 0x00000010 /* timer is called from tasklet */
#define SNDRV_TIMER_HW_WORK 0x00000010 /* timer is called from work */

#define SNDRV_TIMER_IFLG_SLAVE 0x00000001
#define SNDRV_TIMER_IFLG_RUNNING 0x00000002
#define SNDRV_TIMER_IFLG_START 0x00000004
#define SNDRV_TIMER_IFLG_AUTO 0x00000008 /* auto restart */
#define SNDRV_TIMER_IFLG_FAST 0x00000010 /* fast callback (do not use tasklet) */
#define SNDRV_TIMER_IFLG_FAST 0x00000010 /* fast callback (do not use work) */
#define SNDRV_TIMER_IFLG_CALLBACK 0x00000020 /* timer callback is active */
#define SNDRV_TIMER_IFLG_EXCLUSIVE 0x00000040 /* exclusive owner - no more instances */
#define SNDRV_TIMER_IFLG_EARLY_EVENT 0x00000080 /* write early event to the poll queue */
Expand Down Expand Up @@ -74,7 +74,7 @@ struct snd_timer {
struct list_head active_list_head;
struct list_head ack_list_head;
struct list_head sack_list_head; /* slow ack list head */
struct tasklet_struct task_queue;
struct work_struct task_work;
int max_instances; /* upper limit of timer instances */
int num_instances; /* current number of timer instances */
};
Expand All @@ -96,7 +96,7 @@ struct snd_timer_instance {
unsigned long ticks; /* auto-load ticks when expired */
unsigned long cticks; /* current ticks */
unsigned long pticks; /* accumulated ticks for callback */
unsigned long resolution; /* current resolution for tasklet */
unsigned long resolution; /* current resolution for work */
unsigned long lost; /* lost ticks */
int slave_class;
unsigned int slave_id;
Expand Down
2 changes: 1 addition & 1 deletion sound/core/hrtimer.c
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ static int snd_hrtimer_stop(struct snd_timer *t)
}

static const struct snd_timer_hardware hrtimer_hw __initconst = {
.flags = SNDRV_TIMER_HW_AUTO | SNDRV_TIMER_HW_TASKLET,
.flags = SNDRV_TIMER_HW_AUTO | SNDRV_TIMER_HW_WORK,
.open = snd_hrtimer_open,
.close = snd_hrtimer_close,
.start = snd_hrtimer_start,
Expand Down
20 changes: 10 additions & 10 deletions sound/core/timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -813,12 +813,12 @@ static void snd_timer_clear_callbacks(struct snd_timer *timer,
}

/*
* timer tasklet
* timer work
*
*/
static void snd_timer_tasklet(struct tasklet_struct *t)
static void snd_timer_work(struct work_struct *work)
{
struct snd_timer *timer = from_tasklet(timer, t, task_queue);
struct snd_timer *timer = container_of(work, struct snd_timer, task_work);
unsigned long flags;

if (timer->card && timer->card->shutdown) {
Expand All @@ -843,7 +843,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
unsigned long resolution;
struct list_head *ack_list_head;
unsigned long flags;
int use_tasklet = 0;
bool use_work = false;

if (timer == NULL)
return;
Expand Down Expand Up @@ -884,7 +884,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
--timer->running;
list_del_init(&ti->active_list);
}
if ((timer->hw.flags & SNDRV_TIMER_HW_TASKLET) ||
if ((timer->hw.flags & SNDRV_TIMER_HW_WORK) ||
(ti->flags & SNDRV_TIMER_IFLG_FAST))
ack_list_head = &timer->ack_list_head;
else
Expand Down Expand Up @@ -919,11 +919,11 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
snd_timer_process_callbacks(timer, &timer->ack_list_head);

/* do we have any slow callbacks? */
use_tasklet = !list_empty(&timer->sack_list_head);
use_work = !list_empty(&timer->sack_list_head);
spin_unlock_irqrestore(&timer->lock, flags);

if (use_tasklet)
tasklet_schedule(&timer->task_queue);
if (use_work)
queue_work(system_highpri_wq, &timer->task_work);
}
EXPORT_SYMBOL(snd_timer_interrupt);

Expand Down Expand Up @@ -967,7 +967,7 @@ int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid,
INIT_LIST_HEAD(&timer->ack_list_head);
INIT_LIST_HEAD(&timer->sack_list_head);
spin_lock_init(&timer->lock);
tasklet_setup(&timer->task_queue, snd_timer_tasklet);
INIT_WORK(&timer->task_work, snd_timer_work);
timer->max_instances = 1000; /* default limit per timer */
if (card != NULL) {
timer->module = card->module;
Expand Down Expand Up @@ -1200,7 +1200,7 @@ static int snd_timer_s_close(struct snd_timer *timer)

static const struct snd_timer_hardware snd_timer_system =
{
.flags = SNDRV_TIMER_HW_FIRST | SNDRV_TIMER_HW_TASKLET,
.flags = SNDRV_TIMER_HW_FIRST | SNDRV_TIMER_HW_WORK,
.resolution = 1000000000L / HZ,
.ticks = 10000000L,
.close = snd_timer_s_close,
Expand Down

0 comments on commit bf08359

Please sign in to comment.