Linux Kernel threads in Device Drivers

Source: Internet
Author: User
Document directory
  • Kthread. h
  • Kthread. c
  • Thread_drv.c
  • Makefile

Purpose

This examples shows how to create and stop a kernel thread.
The driver is implemented as a loadable module. in the init_module () Routine five kernel threads are created. this kernel threads sleep one second, wake up, print a message and fall asleep again. on unload of the module (cleanup_module), the kernel threads are killed.
The example has been tested with linuxkernel 2.4.2 on Intel (UNI processor only) and Alpha Platform (Compaq personal workstation 500au (UNI processor), ds20 and es40 (SMP ).

A version for the 2.2 kernel can be found here. note: depending on the context of the creator of the threads the new threads may inherit properties from the parent you do not want to have. the new version avoids this by havingkeventd"Create the threads. The 2.2. kernel do not have"keventd, So this approach is not implementable there.

Functions in Example
  • start_kthread: Creates a new kernel thread. can be called from any process context but not from interrupt. The functions blocks until the thread started.
  • stop_kthread: Stop the thread. can be called from any process context but the thread to be terminated. cannot be called from interrupt context. The function blocks until the thread terminated.
  • init_kthread: Sets the environment of the new threads. is to be called out of the created thread.
  • exit_kthread: Needs to be called by the thread to be terminated on exit
Creation of new thread

A new thread is createdkernel_thread(). The thread inherits properties from its parents. To make sure that we do not get any weired properties, we letkeventdCreate the new thread.
The new thread is createdstart_kthread(). It uses a semaphore to block until the new thread is running.down()Blocksstart_kthread()Routine until the correspondingup()Call ininit_kthread()Is executed.
The new thread must callinit_kthread()In order to let the Creator continue.

Stop of New thread

stop_kthread()Sets a flag that the thread uses to determine whether do die or not and sends a sigkill to the thread. this signal causes the thread to be woken up. on wakeup it will check for the flag and then terminate itself by callingexit_kthreadAnd returning from the thread function. With a semaphorestop_kthread()Function blocks until the thread terminated.

Initialization of New thread

Within the new created thread,init_kthread()Needs to be called. This function sets a signal mask, initialises a wait queue, the termination flag and sets a new name for the thread. Withup()Call it notifies the creator that the setup is done.

Exit of New thread

When the thread waits es the notification to terminate itself, is calltheexit_kthread()Function. It notifiesstop_kthread()Function that it terminated withup()Call.

The new thread itself

The new thread is implemented inexample_thread()Function. It runs an endless loop (for(;;)). In the loop it falls asleep withinterruptible_sleep_on_timeout()Function. It comes out of this function either when the timeout expires or when a signal got caught.
The "work" in the thread is to print out a message with printk.

Kernel versions

The example has been tested on 2.4.2.

Example device driver code

The example consists of four files: kthread. H, kthread. C, thread_drv.c and a makefile

Kthread. h
#ifndef _KTHREAD_H#define _KTHREAD_H#include <linux/config.h>#include <linux/version.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/tqueue.h>#include <linux/wait.h>#include <asm/unistd.h>#include <asm/semaphore.h>/* a structure to store all information we need   for our thread */typedef struct kthread_struct{        /* private data */        /* linux task structure of thread */        struct task_struct *thread;        /* Task queue need to launch thread */        struct tq_struct tq;        /* function to be started as thread */        void (*function) (struct kthread_struct *kthread);        /* semaphore needed on start and creation of thread. */        struct semaphore startstop_sem;        /* public data */        /* queue thread is waiting on. Gets initialized by           init_kthread, can be used by thread itself.        */        wait_queue_head_t queue;        /* flag to tell thread whether to die or not.           When the thread receives a signal, it must check           the value of terminate and call exit_kthread and terminate           if set.        */        int terminate;        /* additional data to pass to kernel thread */        void *arg;} kthread_t;/* prototypes *//* start new kthread (called by creator) */void start_kthread(void (*func)(kthread_t *), kthread_t *kthread);/* stop a running thread (called by "killer") */void stop_kthread(kthread_t *kthread);/* setup thread environment (called by new thread) */void init_kthread(kthread_t *kthread, char *name);/* cleanup thread environment (called by thread upon receiving termination signal) */void exit_kthread(kthread_t *kthread);#endif
Kthread. c
#include <linux/config.h>#include <linux/version.h>#if defined(MODVERSIONS)#include <linux/modversions.h>#endif#include <linux/kernel.h>#include <linux/sched.h>#include <linux/tqueue.h>#include <linux/wait.h>#include <linux/signal.h>#include <asm/semaphore.h>#include <asm/smplock.h>#include "kthread.h"/* private functions */static void kthread_launcher(void *data){        kthread_t *kthread = data;        kernel_thread((int (*)(void *))kthread->function, (void *)kthread, 0);        }/* public functions *//* create a new kernel thread. Called by the creator. */void start_kthread(void (*func)(kthread_t *), kthread_t *kthread){        /* initialize the semaphore:           we start with the semaphore locked. The new kernel           thread will setup its stuff and unlock it. This           control flow (the one that creates the thread) blocks           in the down operation below until the thread has reached           the up() operation.         */        init_MUTEX_LOCKED(&kthread->startstop_sem);        /* store the function to be executed in the data passed to           the launcher */        kthread->function=func;                /* create the new thread my running a task through keventd */        /* initialize the task queue structure */        kthread->tq.sync = 0;        INIT_LIST_HEAD(&kthread->tq.list);        kthread->tq.routine =  kthread_launcher;        kthread->tq.data = kthread;        /* and schedule it for execution */        schedule_task(&kthread->tq);        /* wait till it has reached the setup_thread routine */        down(&kthread->startstop_sem);               }/* stop a kernel thread. Called by the removing instance */void stop_kthread(kthread_t *kthread){        if (kthread->thread == NULL)        {                printk("stop_kthread: killing non existing thread!/n");                return;        }        /* this function needs to be protected with the big   kernel lock (lock_kernel()). The lock must be           grabbed before changing the terminate   flag and released after the down() call. */        lock_kernel();                /* initialize the semaphore. We lock it here, the           leave_thread call of the thread to be terminated           will unlock it. As soon as we see the semaphore           unlocked, we know that the thread has exited.*/        init_MUTEX_LOCKED(&kthread->startstop_sem);        /* We need to do a memory barrier here to be sure that           the flags are visible on all CPUs.         */        mb();        /* set flag to request thread termination */        kthread->terminate = 1;        /* We need to do a memory barrier here to be sure that           the flags are visible on all CPUs.         */        mb();        kill_proc(kthread->thread->pid, SIGKILL, 1);               /* block till thread terminated */        down(&kthread->startstop_sem);        /* release the big kernel lock */        unlock_kernel();        /* now we are sure the thread is in zombie state. We           notify keventd to clean the process up.        */        kill_proc(2, SIGCHLD, 1);}/* initialize new created thread. Called by the new thread. */void init_kthread(kthread_t *kthread, char *name){        /* lock the kernel. A new kernel thread starts without           the big kernel lock, regardless of the lock state           of the creator (the lock level is *not* inheritated)        */        lock_kernel();        /* fill in thread structure */        kthread->thread = current;        /* set signal mask to what we want to respond */        siginitsetinv(&current->blocked, sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM));        /* initialise wait queue */        init_waitqueue_head(&kthread->queue);        /* initialise termination flag */        kthread->terminate = 0;        /* set name of this process (max 15 chars + 0 !) */        sprintf(current->comm, name);                /* let others run */        unlock_kernel();        /* tell the creator that we are ready and let him continue */        up(&kthread->startstop_sem);}/* cleanup of thread. Called by the exiting thread. */void exit_kthread(kthread_t *kthread){        /* we are terminating *//* lock the kernel, the exit will unlock it */        lock_kernel();        kthread->thread = NULL;        mb();        /* notify the stop_kthread() routine that we are terminating. */up(&kthread->startstop_sem);/* the kernel_thread that called clone() does a do_exit here. *//* there is no race here between execution of the "killer" and real termination   of the thread (race window between up and do_exit), since both the   thread and the "killer" function are running with the kernel lock held.   The kernel lock will be freed after the thread exited, so the code   is really not executed anymore as soon as the unload functions gets   the kernel lock back.   The init process may not have made the cleanup of the process here,   but the cleanup can be done safely with the module unloaded.*/}
Thread_drv.c
#include <linux/config.h>#include <linux/version.h>#include <linux/module.h>#if defined(MODVERSIONS)#include <linux/modversions.h>#endif#include <linux/kernel.h>#include <linux/string.h>#include <linux/errno.h>#include <linux/sched.h>#include "kthread.h"#define NTHREADS 5/* the variable that contains the thread data */kthread_t example[NTHREADS];/* prototype for the example thread */static void example_thread(kthread_t *kthread);/* load the module */int init_module(void){        int i;                /* create new kernel threads */for (i=0; i <NTHREADS; i++)                start_kthread(example_thread, &example[i]);                return(0);}/* remove the module */void cleanup_module(void){        int i;                /* terminate the kernel threads */for (i=0; i<NTHREADS; i++)                stop_kthread(&example[i]);                return;}/* this is the thread function that we are executing */static void example_thread(kthread_t *kthread){        /* setup the thread environment */        init_kthread(kthread, "example thread");                printk("hi, here is the kernel thread/n");                /* an endless loop in which we are doing our work */        for(;;)        {                /* fall asleep for one second */                interruptible_sleep_on_timeout(&kthread->queue, HZ);                /* We need to do a memory barrier here to be sure that                   the flags are visible on all CPUs.                 */                 mb();                                /* here we are back from sleep, either due to the timeout                   (one second), or because we caught a signal.                */                if (kthread->terminate)                {                        /* we received a request to terminate ourself */                        break;                    }                                /* this is normal work to do */                printk("example thread: thread woke up/n");        }        /* here we go only in case of termination of the thread */        /* cleanup the thread, leave */        exit_kthread(kthread);/* returning from the thread here calls the exit functions */}
Makefile
# set to your kernel treeKERNEL  = /usr/src/linux# get the linux architecture. Needed to find proper include file for CFLAGSARCH=$(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)# set default flags to compile moduleCFLAGS = -D__KERNEL__ -DMODULE -I$(KERNEL)/includeCFLAGS+= -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strict-aliasingall:thread_mod.o# get configuration of kernelinclude $(KERNEL)/.config# modify CFLAGS with architecture specific flagsinclude $(KERNEL)/arch/${ARCH}/Makefile# enable the module versions, if configured in kernel source treeifdef CONFIG_MODVERSIONSCFLAGS+= -DMODVERSIONS -include $(KERNEL)/include/linux/modversions.hendif# enable SMP, if configured in kernel source treeifdef CONFIG_SMPCFLAGS+= -D__SMP__endif# note: we are compiling the driver object file and then linking# we link it into the module. With just one object file as in# this example this is not needed. We can just load the object# file produced by gcc # link the thread driver modulethread_mod.o:     thread_drv.o kthread.old -r -o thread_mod.o thread_drv.o kthread.o# compile the kthread object filekthread.o:kthread.c kthread.hgcc $(CFLAGS) -c kthread.c# compile the thread driverthread_drv.o:     thread_drv.c kthread.hgcc $(CFLAGS) -c thread_drv.cclean:rm -f *.o
Bugs

The Code assumes thatkeventdIs running with PID 2.

Comments, corrections

Please send comments, corrections etc. to the address below.
Http://blog.csdn.net/relianceslee/archive/2006/07/21/952829.aspx
Http://blog.csdn.net/absurd/archive/2006/07/25/976820.aspx

Previous Article: TCP/IP network Basics

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.