Question regarding dynamic allocated tasklet
Hi Guys, I am Abhinav, new to this mailing list. Have some query on tasklet. Going Jerry Cooperstein's LDD book chapter-20 (Interrupt handling and deferrable functions) lab exercises. Attached is the snapshot of problem-2,3. I am referring here to only tasklet. Solution to problem for tasklet provided is below. ------------------------------------------------------------ -------------------------------- static void t_fun(unsigned long t_arg) { struct my_dat *data = (struct my_dat *)t_arg; atomic_inc(&counter_bh); pr_info( "In BH: counter_th = %d, counter_bh = %d, jiffies=%ld, %ld\n", atomic_read(&counter_th), atomic_read(&counter_bh), data->jiffies, jiffies); } static DECLARE_TASKLET(t_name, t_fun, (unsigned long)&my_data); /* initialize tasklet */ static irqreturn_t my_interrupt(int irq, void *dev_id) { struct my_dat *data = (struct my_dat *)dev_id; atomic_inc(&counter_th); data->jiffies = jiffies; tasklet_schedule(&t_name); mdelay(delay); /* hoke up a delay to try to cause pileup */ return IRQ_NONE; /* we return IRQ_NONE because we are just observing */ } module_init(my_generic_init); module_exit(my_generic_exit); ------------------------------------------------------------ ------------------------------------- Above solution will miss some bottom halves. To solve this problem, a solution is provided using dynamically allocated tasklet as below ------------------------------------------------------------------------- static void t_fun(unsigned long t_arg) { struct my_dat *data = (struct my_dat *)t_arg; atomic_inc(&counter_bh); pr_info("In BH: counter_th = %d, counter_bh = %d, jiffies=%ld, %ld\n", atomic_read(&counter_th), atomic_read(&counter_bh), data->jiffies, jiffies); kfree(data); } static irqreturn_t my_interrupt(int irq, void *dev_id) { struct tasklet_struct *t; struct my_dat *data; data = (struct my_dat *)kmalloc(sizeof(struct my_dat), GFP_ATOMIC); t = &data->tsk; data->jiffies = jiffies; tasklet_init(t, t_fun, (unsigned long)data); atomic_inc(&counter_th); tasklet_schedule(t); mdelay(delay); /* hoke up a delay to try to cause pileup */ return IRQ_NONE; /* we return IRQ_NONE because we are just observing */ } module_init(my_generic_init); module_exit(my_generic_exit); ------------------------------------------------------------------------- Above solution will not miss any bottom halves. Can somebody explains me why above solution is working ? What is so special about dynamic tasklets ? BR,Abhinav
Hi Abhinav, On Sat, Jun 16, 2018 at 11:52 PM, Abhinav Misra <abhitheextremeeng@gmail.com> wrote:
Hi Guys,
I am Abhinav, new to this mailing list.
Have some query on tasklet. Going Jerry Cooperstein's LDD book chapter-20 (Interrupt handling and deferrable functions) lab exercises.
Attached is the snapshot of problem-2,3. I am referring here to only tasklet.
Solution to problem for tasklet provided is below.
-------------------------------------------------------------------------------------------- static void t_fun(unsigned long t_arg) { struct my_dat *data = (struct my_dat *)t_arg; atomic_inc(&counter_bh); pr_info( "In BH: counter_th = %d, counter_bh = %d, jiffies=%ld, %ld\n", atomic_read(&counter_th), atomic_read(&counter_bh), data->jiffies, jiffies); }
static DECLARE_TASKLET(t_name, t_fun, (unsigned long)&my_data);
/* initialize tasklet */ static irqreturn_t my_interrupt(int irq, void *dev_id) { struct my_dat *data = (struct my_dat *)dev_id; atomic_inc(&counter_th); data->jiffies = jiffies; tasklet_schedule(&t_name); mdelay(delay); /* hoke up a delay to try to cause pileup */ return IRQ_NONE; /* we return IRQ_NONE because we are just observing */ }
This is general one where the tasklet is initialized either in Init or probe. There is only one tasklet created here which is scheduled on IRQ.
module_init(my_generic_init); module_exit(my_generic_exit);
-------------------------------------------------------------------------------------------------
Above solution will miss some bottom halves. To solve this problem, a solution is provided using dynamically allocated tasklet as below
------------------------------------------------------------------------- static void t_fun(unsigned long t_arg) { struct my_dat *data = (struct my_dat *)t_arg; atomic_inc(&counter_bh); pr_info("In BH: counter_th = %d, counter_bh = %d, jiffies=%ld, %ld\n", atomic_read(&counter_th), atomic_read(&counter_bh), data->jiffies, jiffies); kfree(data); }
static irqreturn_t my_interrupt(int irq, void *dev_id) { struct tasklet_struct *t; struct my_dat *data;
data = (struct my_dat *)kmalloc(sizeof(struct my_dat), GFP_ATOMIC); t = &data->tsk; data->jiffies = jiffies;
tasklet_init(t, t_fun, (unsigned long)data);
atomic_inc(&counter_th); tasklet_schedule(t); mdelay(delay); /* hoke up a delay to try to cause pileup */ return IRQ_NONE; /* we return IRQ_NONE because we are just observing */ }
This part of code initializes a new tasklet everytime on the IRQ. Hence each time the processor services the IRQ there is a new tasklet is getting created however the function remains the same.
module_init(my_generic_init); module_exit(my_generic_exit);
-------------------------------------------------------------------------
Above solution will not miss any bottom halves. Can somebody explains me why above solution is working ? What is so special about dynamic tasklets ?
The solution works because the new tasklet is created everytime with the same cb function. Note that the function should be fully re-entrant for such use-cases which is done using the local variable - arg/data in your case.
BR,Abhinav
_______________________________________________ Kernelnewbies mailing list Kernelnewbies@kernelnewbies.org https://lists.kernelnewbies.org/mailman/listinfo/kernelnewbies
participants (2)
-
Abhinav Misra -
priyaranjan