2005-04-17 02:20:36 +04:00
/* Kernel thread helper functions.
* Copyright ( C ) 2004 IBM Corporation , Rusty Russell .
*
2007-05-09 13:34:32 +04:00
* Creation is done via kthreadd , so that we get a clean environment
2005-04-17 02:20:36 +04:00
* even if we ' re invoked from userspace ( think modprobe , hotplug cpu ,
* etc . ) .
*/
# include <linux/sched.h>
# include <linux/kthread.h>
# include <linux/completion.h>
# include <linux/err.h>
# include <linux/unistd.h>
# include <linux/file.h>
# include <linux/module.h>
2006-03-23 14:00:24 +03:00
# include <linux/mutex.h>
2005-04-17 02:20:36 +04:00
2008-01-25 23:08:33 +03:00
# define KTHREAD_NICE_LEVEL (-5)
2007-05-09 13:34:32 +04:00
static DEFINE_SPINLOCK ( kthread_create_lock ) ;
static LIST_HEAD ( kthread_create_list ) ;
struct task_struct * kthreadd_task ;
2005-04-17 02:20:36 +04:00
struct kthread_create_info
{
2007-05-09 13:34:32 +04:00
/* Information passed to kthread() from kthreadd. */
2005-04-17 02:20:36 +04:00
int ( * threadfn ) ( void * data ) ;
void * data ;
struct completion started ;
2007-05-09 13:34:32 +04:00
/* Result passed back to kthread_create() from kthreadd. */
2005-04-17 02:20:36 +04:00
struct task_struct * result ;
struct completion done ;
2006-11-22 17:55:48 +03:00
2007-05-09 13:34:32 +04:00
struct list_head list ;
2005-04-17 02:20:36 +04:00
} ;
struct kthread_stop_info
{
struct task_struct * k ;
int err ;
struct completion done ;
} ;
/* Thread stopping is done by setthing this var: lock serializes
* multiple kthread_stop calls . */
2006-03-23 14:00:24 +03:00
static DEFINE_MUTEX ( kthread_stop_lock ) ;
2005-04-17 02:20:36 +04:00
static struct kthread_stop_info kthread_stop_info ;
2006-06-25 16:49:19 +04:00
/**
* kthread_should_stop - should this kthread return now ?
*
2007-02-10 12:45:59 +03:00
* When someone calls kthread_stop ( ) on your kthread , it will be woken
2006-06-25 16:49:19 +04:00
* and this will return true . You should then return , and your return
* value will be passed through to kthread_stop ( ) .
*/
2005-04-17 02:20:36 +04:00
int kthread_should_stop ( void )
{
return ( kthread_stop_info . k = = current ) ;
}
EXPORT_SYMBOL ( kthread_should_stop ) ;
static int kthread ( void * _create )
{
struct kthread_create_info * create = _create ;
int ( * threadfn ) ( void * data ) ;
void * data ;
int ret = - EINTR ;
2007-05-09 13:34:32 +04:00
/* Copy data: it's on kthread's stack */
2005-04-17 02:20:36 +04:00
threadfn = create - > threadfn ;
data = create - > data ;
/* OK, tell user we're spawned, wait for stop or wakeup */
2007-05-24 00:57:27 +04:00
__set_current_state ( TASK_UNINTERRUPTIBLE ) ;
2005-04-17 02:20:36 +04:00
complete ( & create - > started ) ;
schedule ( ) ;
if ( ! kthread_should_stop ( ) )
ret = threadfn ( data ) ;
/* It might have exited on its own, w/o kthread_stop. Check. */
if ( kthread_should_stop ( ) ) {
kthread_stop_info . err = ret ;
complete ( & kthread_stop_info . done ) ;
}
return 0 ;
}
2007-05-09 13:34:32 +04:00
static void create_kthread ( struct kthread_create_info * create )
2005-04-17 02:20:36 +04:00
{
int pid ;
/* We want our own signal handler (we take no signals by default). */
pid = kernel_thread ( kthread , create , CLONE_FS | CLONE_FILES | SIGCHLD ) ;
if ( pid < 0 ) {
create - > result = ERR_PTR ( pid ) ;
} else {
2008-01-25 23:08:33 +03:00
struct sched_param param = { . sched_priority = 0 } ;
2005-04-17 02:20:36 +04:00
wait_for_completion ( & create - > started ) ;
2006-03-25 14:07:48 +03:00
read_lock ( & tasklist_lock ) ;
2005-04-17 02:20:36 +04:00
create - > result = find_task_by_pid ( pid ) ;
2006-03-25 14:07:48 +03:00
read_unlock ( & tasklist_lock ) ;
2008-01-25 23:08:33 +03:00
/*
* root may have changed our ( kthreadd ' s ) priority or CPU mask .
* The kernel thread should not inherit these properties .
*/
sched_setscheduler ( create - > result , SCHED_NORMAL , & param ) ;
set_user_nice ( create - > result , KTHREAD_NICE_LEVEL ) ;
set_cpus_allowed ( create - > result , CPU_MASK_ALL ) ;
2005-04-17 02:20:36 +04:00
}
complete ( & create - > done ) ;
}
2006-06-25 16:49:19 +04:00
/**
* kthread_create - create a kthread .
* @ threadfn : the function to run until signal_pending ( current ) .
* @ data : data ptr for @ threadfn .
* @ namefmt : printf - style name for the thread .
*
* Description : This helper function creates and names a kernel
* thread . The thread will be stopped : use wake_up_process ( ) to start
* it . See also kthread_run ( ) , kthread_create_on_cpu ( ) .
*
* When woken , the thread will run @ threadfn ( ) with @ data as its
2007-02-10 12:45:59 +03:00
* argument . @ threadfn ( ) can either call do_exit ( ) directly if it is a
2006-06-25 16:49:19 +04:00
* standalone thread for which noone will call kthread_stop ( ) , or
* return when ' kthread_should_stop ( ) ' is true ( which means
* kthread_stop ( ) has been called ) . The return value should be zero
* or a negative error number ; it will be passed to kthread_stop ( ) .
*
* Returns a task_struct or ERR_PTR ( - ENOMEM ) .
*/
2005-04-17 02:20:36 +04:00
struct task_struct * kthread_create ( int ( * threadfn ) ( void * data ) ,
void * data ,
const char namefmt [ ] ,
. . . )
{
struct kthread_create_info create ;
create . threadfn = threadfn ;
create . data = data ;
init_completion ( & create . started ) ;
init_completion ( & create . done ) ;
2007-05-09 13:34:32 +04:00
spin_lock ( & kthread_create_lock ) ;
list_add_tail ( & create . list , & kthread_create_list ) ;
spin_unlock ( & kthread_create_lock ) ;
2008-04-29 11:59:23 +04:00
wake_up_process ( kthreadd_task ) ;
2007-05-09 13:34:32 +04:00
wait_for_completion ( & create . done ) ;
2005-04-17 02:20:36 +04:00
if ( ! IS_ERR ( create . result ) ) {
va_list args ;
va_start ( args , namefmt ) ;
vsnprintf ( create . result - > comm , sizeof ( create . result - > comm ) ,
namefmt , args ) ;
va_end ( args ) ;
}
return create . result ;
}
EXPORT_SYMBOL ( kthread_create ) ;
2006-06-25 16:49:19 +04:00
/**
* kthread_bind - bind a just - created kthread to a cpu .
* @ k : thread created by kthread_create ( ) .
* @ cpu : cpu ( might not be online , must be possible ) for @ k to run on .
*
* Description : This function is equivalent to set_cpus_allowed ( ) ,
* except that @ cpu doesn ' t need to be online , and the thread must be
2007-02-10 12:45:59 +03:00
* stopped ( i . e . , just returned from kthread_create ( ) ) .
2006-06-25 16:49:19 +04:00
*/
2005-04-17 02:20:36 +04:00
void kthread_bind ( struct task_struct * k , unsigned int cpu )
{
2007-05-24 00:57:27 +04:00
if ( k - > state ! = TASK_UNINTERRUPTIBLE ) {
WARN_ON ( 1 ) ;
return ;
}
2005-04-17 02:20:36 +04:00
/* Must have done schedule() in kthread() before we set_task_cpu */
wait_task_inactive ( k ) ;
set_task_cpu ( k , cpu ) ;
k - > cpus_allowed = cpumask_of_cpu ( cpu ) ;
2008-02-12 21:30:05 +03:00
k - > rt . nr_cpus_allowed = 1 ;
2005-04-17 02:20:36 +04:00
}
EXPORT_SYMBOL ( kthread_bind ) ;
2006-06-25 16:49:19 +04:00
/**
* kthread_stop - stop a thread created by kthread_create ( ) .
* @ k : thread created by kthread_create ( ) .
*
* Sets kthread_should_stop ( ) for @ k to return true , wakes it , and
* waits for it to exit . Your threadfn ( ) must not call do_exit ( )
* itself if you use this function ! This can also be called after
* kthread_create ( ) instead of calling wake_up_process ( ) : the thread
* will exit without calling threadfn ( ) .
*
* Returns the result of threadfn ( ) , or % - EINTR if wake_up_process ( )
* was never called .
*/
2005-04-17 02:20:36 +04:00
int kthread_stop ( struct task_struct * k )
{
int ret ;
2006-03-23 14:00:24 +03:00
mutex_lock ( & kthread_stop_lock ) ;
2005-04-17 02:20:36 +04:00
/* It could exit after stop_info.k set, but before wake_up_process. */
get_task_struct ( k ) ;
/* Must init completion *before* thread sees kthread_stop_info.k */
init_completion ( & kthread_stop_info . done ) ;
2005-05-01 19:58:47 +04:00
smp_wmb ( ) ;
2005-04-17 02:20:36 +04:00
/* Now set kthread_should_stop() to true, and wake it up. */
kthread_stop_info . k = k ;
2006-07-14 11:24:05 +04:00
wake_up_process ( k ) ;
2005-04-17 02:20:36 +04:00
put_task_struct ( k ) ;
/* Once it dies, reset stop ptr, gather result and we're done. */
wait_for_completion ( & kthread_stop_info . done ) ;
kthread_stop_info . k = NULL ;
ret = kthread_stop_info . err ;
2006-03-23 14:00:24 +03:00
mutex_unlock ( & kthread_stop_lock ) ;
2005-04-17 02:20:36 +04:00
return ret ;
}
2006-07-14 11:24:05 +04:00
EXPORT_SYMBOL ( kthread_stop ) ;
2005-04-17 02:20:36 +04:00
2007-07-31 11:39:16 +04:00
int kthreadd ( void * unused )
2005-04-17 02:20:36 +04:00
{
2007-05-09 13:34:32 +04:00
struct task_struct * tsk = current ;
2005-04-17 02:20:36 +04:00
2007-07-31 11:39:16 +04:00
/* Setup a clean context for our children to inherit. */
2007-05-09 13:34:32 +04:00
set_task_comm ( tsk , " kthreadd " ) ;
2007-05-09 13:34:37 +04:00
ignore_signals ( tsk ) ;
2008-01-25 23:08:33 +03:00
set_user_nice ( tsk , KTHREAD_NICE_LEVEL ) ;
2007-05-09 13:34:37 +04:00
set_cpus_allowed ( tsk , CPU_MASK_ALL ) ;
2007-05-09 13:34:32 +04:00
current - > flags | = PF_NOFREEZE ;
for ( ; ; ) {
set_current_state ( TASK_INTERRUPTIBLE ) ;
if ( list_empty ( & kthread_create_list ) )
schedule ( ) ;
__set_current_state ( TASK_RUNNING ) ;
spin_lock ( & kthread_create_lock ) ;
while ( ! list_empty ( & kthread_create_list ) ) {
struct kthread_create_info * create ;
create = list_entry ( kthread_create_list . next ,
struct kthread_create_info , list ) ;
list_del_init ( & create - > list ) ;
spin_unlock ( & kthread_create_lock ) ;
create_kthread ( create ) ;
spin_lock ( & kthread_create_lock ) ;
}
spin_unlock ( & kthread_create_lock ) ;
}
return 0 ;
}