//------------------------------------------------------------------- // freydemo.c // // Demonstrates use of the 'keventd' daemon to start and stop // kernel threads, adapted from a demo-module by Martin Frey: // // http://www.scs.ch/~frey/linux/kernelthreads.html // // NOTE: Developed and tested with Linux kernel version 2.4.4. // // programmer: ALLAN CRUSE // written on: 15 MAR 2002 // revised on: 15 NOV 2004 -- for Linux kernel version 2.4.26. //------------------------------------------------------------------- #include // for init_module() #include // for schedule_task() #include // for lock_kernel() #define NTHREADS 5 // number of kernel threads typedef struct kthread_struct { struct task_struct *thread; struct tq_struct tq; void (*function)( struct kthread_struct *); struct semaphore startstop_sem; wait_queue_head_t wq; int terminate; void *arg; } kthread_t; static char modname[] = "freydemo"; static pid_t keventd_pid; // PID for 'keventd' daemon static kthread_t example[ NTHREADS ]; // array of thread structures static void kthread_launcher( void *data ) { kthread_t *kthread = data; kernel_thread( (int (*)(void*))kthread->function, (void*)kthread, 0 ); } void start_kthread( void (*func)( kthread_t *), kthread_t *kthread ) { static int count = 0; init_MUTEX_LOCKED( &kthread->startstop_sem ); kthread->function = func; kthread->arg = (void *)(++count); kthread->tq.sync = 0; INIT_LIST_HEAD( &kthread->tq.list ); kthread->tq.routine = kthread_launcher; kthread->tq.data = kthread; schedule_task( &kthread->tq ); down( &kthread->startstop_sem ); } void stop_kthread( kthread_t *kthread ) { if ( kthread->thread == NULL ) { printk( "<1> stop_kthread: killing nonexistent thread\n" ); return; } lock_kernel(); init_MUTEX_LOCKED( &kthread->startstop_sem ); mb(); kthread->terminate = 1; mb(); kill_proc( kthread->thread->pid, SIGKILL, 1 ); down( &kthread->startstop_sem ); unlock_kernel(); kill_proc( keventd_pid, SIGCHLD, 1 ); } void init_kthread( kthread_t *kthread, const char *name ) { lock_kernel(); kthread->thread = current; siginitsetinv( ¤t->blocked, sigmask( SIGKILL )|sigmask( SIGINT )|sigmask( SIGTERM ) ); init_waitqueue_head( &kthread->wq ); kthread->terminate = 0; sprintf( ¤t->comm[0], "%s #%d", name, kthread->arg ); unlock_kernel(); up( &kthread->startstop_sem ); } void exit_kthread( kthread_t *kthread ) { lock_kernel(); kthread->thread = NULL; mb(); up( &kthread->startstop_sem ); unlock_kernel(); // <----???? Frey omits this } //------------------------------------------------------------------- static void our_example_thread( kthread_t *kthread ) { init_kthread( kthread, "example thread" ); printk( "<1> Hi, I am kernel thread #%d\n", kthread->arg ); for (;;) { interruptible_sleep_on_timeout( &kthread->wq, HZ ); mb(); if ( kthread->terminate ) break; printk( "<1> thread #%d just woke up\n", kthread->arg ); } exit_kthread( kthread ); } int init_module( void ) { struct task_struct *tsk = &init_task; int i; printk( "<1>\nInstalling \'%s\' module\n", modname ); // determine the process-ID for the 'kevent' daemon while ( ( tsk = tsk->next_task ) != current ) if ( strncmp( tsk->comm, "keventd", 7 ) == 0 ) keventd_pid = tsk->pid; if ( !keventd_pid ) return -ESRCH; // start each one of our kernel threads for (i = 0; i < NTHREADS; i++) start_kthread( our_example_thread, &example[i] ); return 0; // SUCCESS } void cleanup_module( void ) { int i; // stop each one of our kernel threads for (i = 0; i < NTHREADS; i++) stop_kthread( &example[i] ); printk( "<1>Removing \'%s\' module\n", modname ); } MODULE_LICENSE("GPL");