What are Kernel threads
The purpose of a kernel threads is to make a tasks which will run in the background. Usually kernel threads wait for some asynchronous events and then wake up to serve them. For example, the kswapd is kernel thread which runs in the background and wait for expiration of a swap timer, then it handles swapping memory to disk if the number of free pages in the system is low.If you type the following in your terminal:
$ ps -aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 185512 6100 ? Ss אוק06 0:04 /lib/systemd/systemd --system --deserialize 28
root 2 0.0 0.0 0 0 ? S אוק06 0:00 [kthreadd]
root 3 0.0 0.0 0 0 ? S אוק06 0:00 [ksoftirqd/0]
root 5 0.0 0.0 0 0 ? S< אוק06 0:00 [kworker/0:0H]
root 7 0.0 0.0 0 0 ? S אוק06 0:23 [rcu_sched]
root 8 0.0 0.0 0 0 ? S אוק06 0:00 [rcu_bh]
root 9 0.0 0.0 0 0 ? S אוק06 0:00 [migration/0]
root 10 0.0 0.0 0 0 ? S אוק06 0:00 [watchdog/0]
root 11 0.0 0.0 0 0 ? S אוק06 0:00 [watchdog/1]
root 12 0.0 0.0 0 0 ? S אוק06 0:00 [migration/1]
root 13 0.0 0.0 0 0 ? S אוק06 0:00 [ksoftirqd/1]
...
All this processes which name is surrounded by square brackets are kernel threads.
Lets see some code:
Low level kernel thread usage
I will begin, by showing you a low level thread API, then we look at higher level API which should be usually used.This is how to create a linux thread:
ret = kernel_thread(mythread, NULL,
CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD);
There parameters we pass here tells which resources should be shared between the parent thread and the child thread. For example - CLONE_FILES, share opened files, CLONE_SIGHAND, share signal handlers.
Each thread in Linux has a single parent and usually the new created threads are re-parented to kthreadd thread, to avoid the new thread to become a zombie if a parent process dies without waiting for its child to exit.
static DECLARE_WAIT_QUEUE_HEAD(myevent_waitqueue); rwlock_t myevent_lock; static int mythread(void *unused) { unsigned int event_id = 0; DECLARE_WAITQUEUE(wait, current); /* performs initial housekeeping and changes the parent of the calling thread
to a kernel thread called kthreadd */ daemonize("mythread"); /* all signals are blocked by default, so we need to enable a particular signal. */
allow_signal(SIGKILL);
/* The thread sleeps on this wait queue until it's woken up */ add_wait_queue(&myevent_waitqueue, &wait); for (;;)
{
/* Request to opt out of the scheduler run queue */
set_current_state(TASK_INTERRUPTIBLE);
/* asks the scheduler to choose and run a new task from its run queue */
schedule();
/* At this point scheduler executes another task and it will not execute the current kthread anymore. */
/* Die if SIGKILL received, it is the only signal that may be received... */ if (signal_pending(current)) { break;
}
/* The thread is put back into the scheduler run queue. This could only happend because of an event over the wait queue. */ read_lock(&myevent_lock); /* Do something here... */
read_unlock(&myevent_lock);
}
/*
Changed to TASK_RUNNING, so there is no race condition even if the wake up occurs
between the time the task state is set to TASK_INTERRUPTIBLE and the time schedule()
is called.
*/
set_current_state(TASK_RUNNING);
remove_wait_queue(&myevent_waitqueue, &wait); return 0; } |
Notes about kthread
Kernel threads may be preempted if the kernel was compiled with CONFIG_PREEMPT flag.A code may prevent preemption, even of the CONFIG_PREEMPT flag, by disabling local interrupts.A kernel thread can be in any of the following process states:
- TASK_RUNNING: In the scheduler run queue, so should run in future.
- TASK_INTERRUPTIBLE: Waiting for an event and is not in the
scheduler run queue. - TASK_UNINTERRUPTIBLE: Receipt of a signal will not put the task back into the run queue.
- TASK_STOPPED: Stopped execution as a result of receiving a signal.
- TASK_TRACED: If traced by application such as strace.
- EXIT_ZOMBIE: His parent didn't wait for it to complete.
- EXIT_DEAD: Exited gracefully.
set_current_state()Selects kthread's state.
To wake up a thread which waits on a wait queue, we use wake_up_interruptible(&myevent_waitqueue) function.
The higher level thread API
This API is actually one of several kernel helper interfaces which exist to make a kernel programmer's life a little easier...#include <linux/kthread.h> static int my_thread(void *unused) { DECLARE_WAITQUEUE(wait, current); while (!kthread_should_stop()) { /* ... */ } __set_current_state(TASK_RUNNING); remove_wait_queue(&my_thread_wait, &wait); return 0; } void my_thread_init(void) { my_task = kthread_create(my_thread, NULL, "%s", "my_thread"); } void my_thread_wakeup(void) { if (my_task) { wake_up_process(my_task); } } void my_thread_release(void) { kthread_stop(my_task); }
This is a more proper way to handle threads.
This is for today, thanks for reading!
No comments:
Post a Comment