From: Vladimir Kondratiev <vladimir.kondratiev@intel.com>
To: linux-kernel@vger.kernel.org
Subject: resource leak in kernel_thread()
Date: Thu, 14 Aug 2003 22:12:28 +0300 [thread overview]
Message-ID: <3F3BDF1C.9080500@intel.com> (raw)
I need to spawn and terminate kernel thread from the module quite often.
At any given time, only one thread is alive. There are events that
triggers thread creation and termination.
I found that, if I create/terminate thread many times (3000 - 4000
times), system get to the stage when it can't create new process. I
checked that, if I terminate one (already running) process after getting
to this stage, I can create one more kernel thread, then system return
to the state when no more processes can be created.
I use vanilla 2.4.20 kernel.
kernel_thread() start returning -11, which is -EAGAIN.
I must be doing something stupid, but I looked at kernel thread usage in
the kernel code and found it is the same as in my example (to extent I
can understand :-) ).
I will appreciate any help WRT proper kernel_thread usage. Please, CC me
(vladimir.kondratiev@intel.com) in your reply since I am not subscribed
to the list.
To simulate this situation, I created simple example. Following code is
module that creates/terminates thread. To model external event that will
trigger creation/termination, I use "/proc/kthread" file. The same file
used to get some statistics. To create thread, one need to write "+" to
the file, to terminate - "-". I run it on single CPU, so I removed all
kernel_lock() related code.
To execute the test, run the following script. After some 3000-4000
threads your system will be unable to create processes.
---kthread.sh begin---
#!/bin/sh
f="/proc/kthread"
function start () {
echo "+" > $f
}
function stop () {
echo "-" > $f
}
function display () {
clear
cat $f
}
sudo /sbin/insmod kthread.o
while true; do start; display; stop; done
---kthread.sh end---
---Makefile begin---
ifneq ($(KERNELRELEASE),)
obj-m := kthread.o
kthread-objs := kthread-main.o
include $(TOPDIR)/Rules.make
$(obj-m) : $($(obj-m:.o=-objs)) $(lib)
$(LD) -r -o $@ $($(obj-m:.o=-objs)) $(lib)
else
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
endif
---Makefile end---
---kthread-main.c begin---
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/proc_fs.h>
#include <linux/vmalloc.h>
#include <asm/uaccess.h>
typedef struct kt_priv_struct {
int nthreads; /**< let's count how many times kernel_thread succeeded */
int pid;
wait_queue_head_t wq; /**< kthread sleep here */
struct completion exited;
__u32 volatile status;
} kt_priv_t;
static kt_priv_t the_data;
static int kt_thread(void* arg)
{
kt_priv_t* priv=(kt_priv_t*)arg;
daemonize();
reparent_to_init();
snprintf(current->comm,sizeof(current->comm),"kth_%d",priv->nthreads);
++priv->nthreads;
while (!test_bit(0,&priv->status)) {
/* framework for periodical execution */
unsigned long to=HZ; /* timeout for periodical maintenance */
do {
to=interruptible_sleep_on_timeout(&priv->wq,to);
} while ( !signal_pending(current) && to>0 );
if (signal_pending(current)) {
spin_lock_irq(¤t->sigmask_lock);
flush_signals(current);
spin_unlock_irq(¤t->sigmask_lock);
}
/* thread body - for this simple example do nothing */
}
complete_and_exit(&priv->exited,0);
}
static void kt_start(kt_priv_t* priv)
{
if (priv->pid>0) return;
init_completion(&priv->exited);
init_waitqueue_head(&priv->wq);
priv->status=0;
priv->pid=kernel_thread(kt_thread,priv,0);
}
static void kt_stop(kt_priv_t* priv)
{
if (priv->pid>0 && (0==test_and_set_bit(0,&priv->status))) {
kill_proc(priv->pid,SIGHUP,1);
wait_for_completion(&priv->exited);
priv->pid=0;
}
}
static int kt_proc_read(char* buf,char** start,off_t offset,int
count,int* eof,void* data)
{
kt_priv_t* priv=(kt_priv_t*)data;
int len=0;
len+=sprintf(buf+len,"nthreads = %d\n",priv->nthreads);
len+=sprintf(buf+len,"pid = %d\n",priv->pid);
*eof=1;
return len;
}
static int kt_proc_write(struct file *file, const char *buffer,unsigned
long count, void *data)
{
kt_priv_t* priv=(kt_priv_t*)data;
int rc=count;
if (count<1) {
return -EINVAL;
}
char* buf=vmalloc(count+1);
if (!buf) return -ENOMEM;
buf[count]='\0';
if (copy_from_user(buf,buffer,count)) {
rc=-EFAULT;
goto out;
}
switch (buf[0]) {
case '+':
kt_start(priv);
break;
case '-':
kt_stop(priv);
break;
}
out:
vfree(buf);
return rc;
}
static char* kt_proc_name="kthread";
static int kt_mod_init(void)
{
kt_priv_t* priv=&the_data;
memset(priv,0,sizeof(*priv));
struct proc_dir_entry*
p=create_proc_read_entry(kt_proc_name,0666,NULL,kt_proc_read,priv);
if (p) {
SET_MODULE_OWNER(p);
p->write_proc=kt_proc_write;
}
return 0;
}
static void kt_mod_exit(void)
{
kt_stop(&the_data);
remove_proc_entry(kt_proc_name,NULL);
}
module_init(kt_mod_init);
module_exit(kt_mod_exit);
MODULE_AUTHOR("Vladimir Kondratiev <vladimir.kondratiev@intel.com>");
MODULE_DESCRIPTION("Kernel thread example");
MODULE_LICENSE("GPL");
---kthread-main.c end---
reply other threads:[~2003-08-14 19:15 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=3F3BDF1C.9080500@intel.com \
--to=vladimir.kondratiev@intel.com \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.