How to Join a Thread in Linux Kernel

How to join a thread in Linux kernel?

AFAIK there is no equivalent of pthread_join() in kernel. Also, I feel like your pattern (of starting bunch of threads and waiting only for one of them) is not really common in kernel. That being said, there kernel does have few synchronization mechanism that may be used to accomplish your goal.

Note that those mechanisms will not guarantee that the thread finished, they will only let main thread know that they finished doing the work they were supposed to do. It may still take some time to really stop this tread and free all resources.

Semaphores

You can create a locked semaphore, then call down in your main thread. This will put it to sleep. Then you will up this semaphore inside of your thread just before exiting. Something like:

struct semaphore sem;

int func(void *arg) {
struct semaphore *sem = (struct semaphore*)arg; // you could use global instead

// do something

up(sem);
return 0;
}

int init_module(void) {
// some initialization
init_MUTEX_LOCKED(&sem);
kthread_run(&func, (void*) &sem, "Creating thread");
down(&sem); // this will block until thread runs up()
}

This should work but is not the most optimal solution. I mention this as it's a known pattern that is also used in userspace. Semaphores in kernel are designed for cases where it's mostly available and this case has high contention. So a similar mechanism optimized for this case was created.

Completions

You can declare completions using:

struct completion comp;
init_completion(&comp);

or:

DECLARE_COMPLETION(comp);

Then you can use wait_for_completion(&comp); instead of down() to wait in main thread and complete(&comp); instead of up() in your thread.

Here's the full example:

DECLARE_COMPLETION(comp);
struct my_data {
int id;
struct completion *comp;
};

int func(void *arg) {
struct my_data *data = (struct my_data*)arg;
// doing something

if (data->id == 3)
complete(data->comp);

return 0;
}

int init_module(void) {
struct my_data *data[] = kmalloc(sizeof(struct my_data)*N, GFP_KERNEL);

// some initialization
for (int i=0; i<N; i++) {
data[i]->comp = ∁
data[i]->id = i;
kthread_run(func, (void*) data[i], "my_thread%d", i);
}
wait_for_completion(&comp); // this will block until some thread runs complete()
}

Multiple threads

I don't really see why you would start 5 identical threads and only want to wait for 3rd one but of course you could send different data to each thread, with a field describing it's id, and then call up or complete only if this id equals 3. That's shown in the completion example. There are other ways to do this, this is just one of them.

Word of caution

Go read some more about those mechanisms before using any of them. There are some important details I did not write about here. Also those examples are simplified and not tested, they are here just to show the overall idea.

How to join multiple threads in Linux kernel

After some experimentation, this seems to be the best way to simulate a rudimentary thread join in the kernel. I used the completion method, not the semaphore method since I found it more straightforward.

struct my_thread_data {
struct completion *comp;
... // anything else you want to pass through
};

void *foo(void *arg) {
// doing something
return NULL;
}

int init_module(void) {
struct task_struct *threads[5];
struct completion comps[5];
struct my_thread_data data[5];

int i;

for (i=0; i<5; i++) {
init_completion(comps + i);
data[i].comp = comps + i;
thread[i] = kthread_run(&foo, (void*)(data + i), "ThreadName");
}

// wait here until all 5 threads are complete
for (i=0; i<5; i++) {
wait_for_completion(comps + i);
}

// do something else once threads are complete

return 0;
}

How to join an array of threads in C++?

Unhandled exception at 0x76BF40B2 in Learn.exe: Microsoft C++ exception: std::system_error at memory location 0x1DF3F4E0.

That mostly because you created an insane number of threads

thread Threads[10000][1000];

Most systems cannot support that number of threads. This is a typical max number of threads that a Linux system support:

~$ cat /proc/sys/kernel/threads-max
124898

Windows can be different, but most likely not in the range of millions.

What is a Kernel thread?

A kernel thread is a kernel task running only in kernel mode; it usually has not been created by fork() or clone() system calls. An example is kworker or kswapd.

You probably should not implement kernel threads if you don't know what they are.

Google gives many pages about kernel threads, e.g. Frey's page.

How is pthread_join implemented?

Yes that's the general idea. For gory details of a particular implementation take a look at glibc.

Linux Kernel Threads : How to pass the Linux module write function as the function that the thread has to execute?

You can't. Your thread function has to use this format:

int my_thread_function(void *data)

You can call it whatever you want - it doesn't have to be called my_thread_function - and the parameter doesn't have to be called data but it does have to be a void *.

This will not work:

ssize_t exer_write(struct file *pfile, const char __user *buffer, size_t length, loff_t *offset)

I suggest writing a new function to be your thread function:

int exer_write_in_thread(void *data) {
exer_write(???, ???, ???, ???);
return 0;
}

Obviously you have to figure out what arguments you want to call exer_write with.

Communicating between Kernel Threads in Linux

I would strongly advise against keeping the VxWorks architecture on Linux. Kernel thread proliferation is frowned upon, your code will never make it into official kernel tree. Even if you don't care about that, are you 100% sure that you want to develop a driver in a non-standard way ? Things would be much simpler if you would just get rid of these two tasks. BTW, why on earth you need tasks for PCI driver to begin with ?

How can I make kernel thread communication?

You don't say what operating system you're programming on. I'll assume Linux, which is the most common unix system.

There are several good books on Linux kernel programming. Linux Device Drivers is available online as well as on paper. Chapter 5 deals with concurrency; you can jump in directly to chapter 5 though it would be best to skim through at least chapters 1 and 3 first. Subsequent chapters have relevant sections as well (in particular wait queues are discussed in chapter 6).

The Linux kernel concurrency model is built on shared variables. There is a large range of synchronization methods: atomic integer variables, mutual exclusion locks (spinlocks for nonblocking critical sections, semaphores for blocking critical sections), reader-writer locks, condition variables, wait queues, …



Related Topics



Leave a reply



Submit