Crazy Psychild
Crazy Psychild

Reputation: 592

Linux - Control Flow in a linux kernel module

I am learning to write kernel modules and in one of the examples I had to make sure that a thread executed 10 times and exits, so I wrote this according to what I have studied:

#include <linux/module.h>
#include <linux/kthread.h>

struct task_struct *ts;
int flag = 0;
int id = 10;

int function(void *data) {
  int n = *(int*)data;
  set_current_state(TASK_INTERRUPTIBLE);
  schedule_timeout(n*HZ); // after doing this it executed infinitely and i had to reboot 
  while(!kthread_should_stop()) {
    printk(KERN_EMERG "Ding");
  }
  flag = 1;
  return 0;
}

int init_module (void) {
  ts = kthread_run(function, (void *)&id, "spawn");
  return 0;
}

 void cleanup_module(void) {
   if (flag==1) { return; }
   else { if (ts != NULL) kthread_stop(ts);
   }
   return;
 }

MODULE_LICENSE("GPL");

What I want to know is : a) How to make thread execute 10 times like a loop b) How does the control flows in these kind of processes that is if we make it to execute 10 times then does it go back and forth between function and cleanup_module or init_module or what exactly happens?

Upvotes: 0

Views: 286

Answers (1)

Tsyvarev
Tsyvarev

Reputation: 65898

If you control kthread with kthread_stop, the kthread shouldn't exit until be ing stopped (see also that answer). So, after executing all operations, kthread should wait until stopped.

Kernel already implements kthread_worker mechanism, when kthread just executes works, added to it.

DEFINE_KTHREAD_WORKER(worker);

struct my_work
{
    struct kthread_work *work; // 'Base' class
    int n;
};

void do_work(struct kthread_work *work)
{
    struct my_work* w = container_of(work, struct my_work, work);

    printk(KERN_EMERG "Ding %d", w->n);

    // And free work struct at the end
    kfree(w);
}

int init_module (void) {
    int i;
    for(i = 0; i < 10; i++)
    {
        struct my_work* w = kmalloc(sizeof(struct my_work), GFP_KERNEL);
        init_kthread_work(&w->work, &do_work);
        w->n = i + 1;
        queue_kthread_work(&worker, &w->work);
    }
    ts = kthread_run(&kthread_worker_fn, &worker, "spawn");
    return 0;
}

void cleanup_module(void) {
    kthread_stop(ts);
}

Upvotes: 2

Related Questions