Question regarding dynamic allocated tasklet

priyaranjan priyaranjan45678 at gmail.com
Mon Jun 18 23:37:30 EDT 2018


Hi Abhinav,

On Sat, Jun 16, 2018 at 11:52 PM, Abhinav Misra
<abhitheextremeeng at 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 at kernelnewbies.org
> https://lists.kernelnewbies.org/mailman/listinfo/kernelnewbies
>



More information about the Kernelnewbies mailing list