Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ALSA: timer: Replace tasklet with work

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/20200903104131.21097-3-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>

+15 -15
+4 -4
include/sound/timer.h
··· 21 21 #define SNDRV_TIMER_HW_STOP 0x00000002 /* call stop before start */ 22 22 #define SNDRV_TIMER_HW_SLAVE 0x00000004 /* only slave timer (variable resolution) */ 23 23 #define SNDRV_TIMER_HW_FIRST 0x00000008 /* first tick can be incomplete */ 24 - #define SNDRV_TIMER_HW_TASKLET 0x00000010 /* timer is called from tasklet */ 24 + #define SNDRV_TIMER_HW_WORK 0x00000010 /* timer is called from work */ 25 25 26 26 #define SNDRV_TIMER_IFLG_SLAVE 0x00000001 27 27 #define SNDRV_TIMER_IFLG_RUNNING 0x00000002 28 28 #define SNDRV_TIMER_IFLG_START 0x00000004 29 29 #define SNDRV_TIMER_IFLG_AUTO 0x00000008 /* auto restart */ 30 - #define SNDRV_TIMER_IFLG_FAST 0x00000010 /* fast callback (do not use tasklet) */ 30 + #define SNDRV_TIMER_IFLG_FAST 0x00000010 /* fast callback (do not use work) */ 31 31 #define SNDRV_TIMER_IFLG_CALLBACK 0x00000020 /* timer callback is active */ 32 32 #define SNDRV_TIMER_IFLG_EXCLUSIVE 0x00000040 /* exclusive owner - no more instances */ 33 33 #define SNDRV_TIMER_IFLG_EARLY_EVENT 0x00000080 /* write early event to the poll queue */ ··· 74 74 struct list_head active_list_head; 75 75 struct list_head ack_list_head; 76 76 struct list_head sack_list_head; /* slow ack list head */ 77 - struct tasklet_struct task_queue; 77 + struct work_struct task_work; 78 78 int max_instances; /* upper limit of timer instances */ 79 79 int num_instances; /* current number of timer instances */ 80 80 }; ··· 96 96 unsigned long ticks; /* auto-load ticks when expired */ 97 97 unsigned long cticks; /* current ticks */ 98 98 unsigned long pticks; /* accumulated ticks for callback */ 99 - unsigned long resolution; /* current resolution for tasklet */ 99 + unsigned long resolution; /* current resolution for work */ 100 100 unsigned long lost; /* lost ticks */ 101 101 int slave_class; 102 102 unsigned int slave_id;
+1 -1
sound/core/hrtimer.c
··· 114 114 } 115 115 116 116 static const struct snd_timer_hardware hrtimer_hw __initconst = { 117 - .flags = SNDRV_TIMER_HW_AUTO | SNDRV_TIMER_HW_TASKLET, 117 + .flags = SNDRV_TIMER_HW_AUTO | SNDRV_TIMER_HW_WORK, 118 118 .open = snd_hrtimer_open, 119 119 .close = snd_hrtimer_close, 120 120 .start = snd_hrtimer_start,
+10 -10
sound/core/timer.c
··· 813 813 } 814 814 815 815 /* 816 - * timer tasklet 816 + * timer work 817 817 * 818 818 */ 819 - static void snd_timer_tasklet(struct tasklet_struct *t) 819 + static void snd_timer_work(struct work_struct *work) 820 820 { 821 - struct snd_timer *timer = from_tasklet(timer, t, task_queue); 821 + struct snd_timer *timer = container_of(work, struct snd_timer, task_work); 822 822 unsigned long flags; 823 823 824 824 if (timer->card && timer->card->shutdown) { ··· 843 843 unsigned long resolution; 844 844 struct list_head *ack_list_head; 845 845 unsigned long flags; 846 - int use_tasklet = 0; 846 + bool use_work = false; 847 847 848 848 if (timer == NULL) 849 849 return; ··· 884 884 --timer->running; 885 885 list_del_init(&ti->active_list); 886 886 } 887 - if ((timer->hw.flags & SNDRV_TIMER_HW_TASKLET) || 887 + if ((timer->hw.flags & SNDRV_TIMER_HW_WORK) || 888 888 (ti->flags & SNDRV_TIMER_IFLG_FAST)) 889 889 ack_list_head = &timer->ack_list_head; 890 890 else ··· 919 919 snd_timer_process_callbacks(timer, &timer->ack_list_head); 920 920 921 921 /* do we have any slow callbacks? */ 922 - use_tasklet = !list_empty(&timer->sack_list_head); 922 + use_work = !list_empty(&timer->sack_list_head); 923 923 spin_unlock_irqrestore(&timer->lock, flags); 924 924 925 - if (use_tasklet) 926 - tasklet_schedule(&timer->task_queue); 925 + if (use_work) 926 + queue_work(system_highpri_wq, &timer->task_work); 927 927 } 928 928 EXPORT_SYMBOL(snd_timer_interrupt); 929 929 ··· 967 967 INIT_LIST_HEAD(&timer->ack_list_head); 968 968 INIT_LIST_HEAD(&timer->sack_list_head); 969 969 spin_lock_init(&timer->lock); 970 - tasklet_setup(&timer->task_queue, snd_timer_tasklet); 970 + INIT_WORK(&timer->task_work, snd_timer_work); 971 971 timer->max_instances = 1000; /* default limit per timer */ 972 972 if (card != NULL) { 973 973 timer->module = card->module; ··· 1200 1200 1201 1201 static const struct snd_timer_hardware snd_timer_system = 1202 1202 { 1203 - .flags = SNDRV_TIMER_HW_FIRST | SNDRV_TIMER_HW_TASKLET, 1203 + .flags = SNDRV_TIMER_HW_FIRST | SNDRV_TIMER_HW_WORK, 1204 1204 .resolution = 1000000000L / HZ, 1205 1205 .ticks = 10000000L, 1206 1206 .close = snd_timer_s_close,