query regarding kernel daemon

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



I was trying some experiments with the kernel daemon. The experiment works as follows:

 

A daemon sleeps in the background. User can enter a string through the proc interface. Whenever a string is entered, the daemon is woke. The daemon keeps a copy of the last entered string in a variable. Initially the variable is initialized to NULL. When the daemon wakes, it checks if the string entered is same as the previous one or a new string is entered. When the string is entered, in case the new or the old strings are NULL, or in case the entered string is same as the old string the daemon goes back to sleep (with the help of the function interruptible_sleep_on().

 

The problem I am facing is that when I enter the string the second time, the system stalls. I added some sleeps in the code and figured out that when the proc function wakes up the daemon, the system stalls.

 

I have attached the module code with the mail. Any suggestion for the error would be a great help.

 

Shubham

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <asm/uaccess.h>
#include <linux/delay.h>

typedef struct {
	char			*old_file_name;
	int			old_file_name_length;
	char			*new_file_name;
	int			new_file_name_length;
	pid_t			thread_pid;
	int			thread_present;
	wait_queue_head_t	thread_sv;	/*to make the thread sleep on certain condition */
//	wait_queue_head_t	multi_thread_sv[1]; /* in case of multi threading, second thread will sleep until first is awake */
						    /* but will this be possible? a module can be loaded only once!!! */
} thread_struct;

#define prc_file_name "test_proc_file_name"

thread_struct *ts = NULL;

char *file_name = NULL;
int file_name_size = 0;

int my_thread_fun (void *arg) {

	int ret;
	thread_struct *my_thread = (thread_struct *) arg;
	if (!try_module_get(THIS_MODULE)) {
		printk(KERN_INFO "%s:\tunable to get the module\n",__FUNCTION__);
		ret = -EINVAL;
		goto out;
	}
	daemonize("test_thread");
	allow_signal(SIGKILL);
	my_thread->thread_present = 1;
	printk(KERN_INFO "%s:\tthread id = %d name of the old file= %s, name of the new file = %s\n",
				__FUNCTION__, my_thread->thread_pid, my_thread->new_file_name, my_thread->old_file_name);
	for (;;) {
		if (signal_pending(current)) {
			my_thread->thread_pid = 0;
			printk(KERN_INFO "%s:\tgot a signal to commit suicide \n",__FUNCTION__);
			ret = -EINTR;
			goto out;
		}

		if (my_thread->new_file_name == NULL || my_thread->old_file_name == NULL) {
			printk(KERN_INFO "%s:\ttime to sleep as nothing to compare\n",__FUNCTION__);
			interruptible_sleep_on(&my_thread->thread_sv);
		}

		printk(KERN_INFO "%s:\tthread id = %d name of the old file= %s, name of the new file = %s\n",
				__FUNCTION__, my_thread->thread_pid, my_thread->new_file_name, my_thread->old_file_name);
	
		/* adding this continue because the thread may
		 * sleep on the above condition and when it wakes
		 * it needs to check again if the old and new file
		 * name are NULL or not
		 */
		continue;

		if (my_thread->new_file_name != NULL) {
			printk(KERN_INFO "%s:\tname of the new file is %s\n",__FUNCTION__, my_thread->new_file_name);
		}

		if (my_thread->old_file_name != NULL) {
			printk(KERN_INFO "%s:\tname of the old file is %s\n",__FUNCTION__, my_thread->old_file_name);
		}
		
		printk(KERN_INFO "%s:\told file(%s) new file(%s) going for comparision\n",
				__FUNCTION__, my_thread->old_file_name, my_thread->new_file_name);
		ssleep(2);
//		schedule_timeout(HZ);

		if (!memcmp(my_thread->old_file_name, my_thread->new_file_name,my_thread->new_file_name_length)) {
//				(my_thread->old_file_name_length > my_thread->new_file_name_length ?
//				 my_thread->old_file_name_length : my_thread->new_file_name_length))) {
			ssleep(2);
			printk(KERN_INFO "%s:\tname of the new file (%s) is same as old file (%s) sleeping\n",
						__FUNCTION__, my_thread->new_file_name, my_thread->old_file_name);
			interruptible_sleep_on(&my_thread->thread_sv);
		}
		ssleep(2);
		printk(KERN_INFO "%s:\tnew file(%s)\n",__FUNCTION__, my_thread->new_file_name);
//		schedule_timeout(HZ);
		my_thread->old_file_name = my_thread->new_file_name;
		my_thread->old_file_name_length = my_thread->new_file_name_length;
		ssleep(2);
		printk(KERN_INFO "%s:\trounding off\n",__FUNCTION__);
	}
out:
	my_thread->thread_present = 0;
	module_put(THIS_MODULE);
	return ret;
}

int read_proc_file(
	char *buf,
	char **buf_loc,
	off_t offset,
	int buf_len,
	int *eof,
	void *data)
{

	int ret;
	printk(KERN_INFO "%s reading from the proc file %s\n", __FUNCTION__,prc_file_name);
	if (offset > 0) {
		return 0;
	} else {
		memcpy(buf, file_name, file_name_size);
		ret = file_name_size;
	}
	return ret;
}

int write_proc_file (
	struct file *filp,
	const char __user *buf,
	unsigned long len,
	void *data) {

	printk(KERN_INFO "%s:\tlength of file name = %ld\n",__FUNCTION__, len);
	printk(KERN_INFO "%s:\twriting into the proc file\n", __FUNCTION__);
	file_name_size = len;

	file_name = (char *) kmalloc(len, GFP_KERNEL);
	if (copy_from_user(file_name, buf, file_name_size)) {
		return -1;
	}

	/* calling the function to print the page information for this file */
	printk(KERN_INFO "%s:\tname of the file is: %s\n", __FUNCTION__, file_name);
	if (ts && ts->thread_present) {
//		schedule_timeout(HZ);
		ssleep(2);
		printk(KERN_INFO "%s:\ta thread exists and is sleeping. time to wake it and make him do some work\n",
				__FUNCTION__);
		if (ts->old_file_name != NULL) {
			printk(KERN_INFO "old entry exists free the memory it occupies\n");
			kfree(ts->old_file_name);
		}
		printk(KERN_INFO "%s:\tadding the new entries to the daemon structure\n",__FUNCTION__);

//		schedule_timeout(HZ);
		ssleep(2);

		ts->old_file_name = ts->new_file_name;
		ts->old_file_name_length = ts->new_file_name_length;
		ts->new_file_name = file_name;
		ts->new_file_name_length = file_name_size;
		printk(KERN_INFO "%s:\twakkkkkkeeee\n",__FUNCTION__);

//		schedule_timeout(HZ);
		ssleep(2);
		wake_up(&ts->thread_sv);
	}
	return file_name_size;
}

int __init
init_thread_module(void) {

	struct proc_dir_entry   *my_entry;
	ts = (thread_struct *) kmalloc(sizeof(thread_struct), GFP_KERNEL);
	if (ts == NULL) {
		printk(KERN_INFO "%s:\tunable to allocate memory for the thread structure\n",__FUNCTION__);
		return 0;
	}
	ts->new_file_name = NULL;
	ts->old_file_name = NULL;
	init_waitqueue_head(&ts->thread_sv);
	printk(KERN_INFO "%s:\tmodule loaded\n",__FUNCTION__);
	printk(KERN_INFO "%s:\ttrying to initiate a thread\n",__FUNCTION__);

	my_entry = create_proc_entry(prc_file_name, 0644, NULL);
	if (my_entry == NULL) {
		printk(KERN_INFO "%s:\tunable to allocate a proc entry\n",__FUNCTION__);
		return 0;
	}
	my_entry->read_proc = read_proc_file;
	my_entry->write_proc = write_proc_file;
	my_entry->owner = THIS_MODULE;

	ts->thread_pid = kernel_thread(my_thread_fun, (void *) ts,
			(CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD));
	if (ts->thread_pid < 0) {
		printk(KERN_INFO "%s:\tunable to create a thread\n", __FUNCTION__);
	}
	return 0;
}

void __exit
exit_thread_module(void) {

	while (ts->thread_present) {
		/* kill the deamon */
		if (kill_proc(ts->thread_pid, SIGKILL, 1) != 0) {
			printk(KERN_INFO "%s:\tunable to kill the thread. dont know what to do now \n", __FUNCTION__);
		}
	}
	if (ts->new_file_name != NULL)
		kfree(ts->new_file_name);
	if (ts->old_file_name != NULL)
		kfree(ts->old_file_name);
	kfree(ts);
	remove_proc_entry(prc_file_name, NULL);
	printk(KERN_INFO "%s:\ttime to unload the module\n", __FUNCTION__);
	return;
}

module_init(init_thread_module)
module_exit(exit_thread_module)
_______________________________________________
Kernelnewbies mailing list
Kernelnewbies@xxxxxxxxxxxxxxxxx
http://lists.kernelnewbies.org/mailman/listinfo/kernelnewbies

[Index of Archives]     [Newbies FAQ]     [Linux Kernel Mentors]     [Linux Kernel Development]     [IETF Annouce]     [Git]     [Networking]     [Security]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux SCSI]     [Linux ACPI]
  Powered by Linux