All of lore.kernel.org
 help / color / mirror / Atom feed
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(&current->sigmask_lock);
      flush_signals(current);
      spin_unlock_irq(&current->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.