Hi Abhinav, On Sat, Jun 16, 2018 at 11:52 PM, Abhinav Misra <abhitheextremeeng@xxxxxxxxx> 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@xxxxxxxxxxxxxxxxx > https://lists.kernelnewbies.org/mailman/listinfo/kernelnewbies > _______________________________________________ Kernelnewbies mailing list Kernelnewbies@xxxxxxxxxxxxxxxxx https://lists.kernelnewbies.org/mailman/listinfo/kernelnewbies