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