/* waitOne.c * Derived from mod-syscall-242 sample system code illustrating * how to add system calls using a kernel module. * System calls use printk for debugging messages. * System calls here only pass and return simple stack values. * so copy_to_user, copy_from_user are not needed. * * Derived from the no-parameter or result hello-1 example in the * Linux Kernel Module Programmer's Guide for 2.4 Kernel. * * Uses existing unused syscall entries in the sys_call_table. * eventWait is sched_setaffinity 241 * eventSig is sched_getaffinity 242 * * Include file locations * is /usr/src/linux/include/linux * is /usr/src/linux/include/asm * is /usr/include/sys * * Source file locations * sys_call_table[] /usr/src/linux/arch/i386/kernel/entry.S */ /* kernel module programming */ #ifndef MODULE #define MODULE #endif #ifndef LINUX #define LINUX #endif #ifndef __KERNEL__ #define __KERNEL__ #endif #define MAX_BUF 80 #include /* needed by all modules */ #include /* for KERN_ALERT */ #include /* for __NR_futex & other system call numbers */ #include /* current, wake_up_process, schedule, TASK_UNI */ /* The kernel will fill in the call table at dynamic load (insmod) */ extern void *sys_call_table[]; /* prototypes */ asmlinkage int my_eventSig_syscall(void); asmlinkage int my_eventWait_syscall(void); int init_module(void); void cleanup_module(void); /* Wait Queue data structures * Right now I just have zero or one waiting tasks */ struct task_struct *my_eventWait_task = NULL; /* My event signal system call */ /* Needs critical region protected */ /* Why not just use the wake_up kernel functions in sched.h or wait.h ? */ asmlinkage int my_eventSig_syscall(void) { struct task_struct *p; /* to limit race conditions */ printk(KERN_ALERT "my_eventSig_syscall: entering.\n"); if (my_eventWait_task) { printk(KERN_ALERT "my_eventSig_syscall: waking up One task.\n"); p = my_eventWait_task; my_eventWait_task = NULL; wake_up_process(p); printk(KERN_ALERT "my_eventSig_syscall: leaving after wakeup.\n"); return 0; } printk(KERN_ALERT "my_eventSig_syscall: leaving but no process to wake up.\n"); return 1; } /* My event wait system call */ /* Needs critical region protected */ /* Why not just use the sleep_on kernel functions in sched.h or wait.h ? */ asmlinkage int my_eventWait_syscall(void) { printk(KERN_ALERT "my_eventWait_syscall: entering.\n"); if (!my_eventWait_task) { my_eventWait_task = current; printk(KERN_ALERT "my_eventWait: One task going to sleep.\n"); current->state = TASK_UNINTERRUPTIBLE; schedule(); printk(KERN_ALERT "my_eventWait_syscall: leaving after wakeup.\n"); return 0; } printk(KERN_ALERT "my_eventWait_syscall: leaving without blocking wait.\n"); return 1; } /* Original system call for NR_sched_setaffinity sys.c of src/linux/kernel */ asmlinkage long (*original_call_241) (void); /* Original system call for NR_sched_getaffinity sys.c of src/linux/kernel */ asmlinkage long (*original_call_242) (void); /* Initialize the module at insmod - insert the new system calls */ int init_module(void) { printk(KERN_ALERT "waitOne module loaded\n"); /* save the original syscall entry and insert our own entry */ original_call_241 = sys_call_table[__NR_sched_setaffinity]; original_call_242 = sys_call_table[__NR_sched_getaffinity]; sys_call_table[__NR_sched_setaffinity] = my_eventWait_syscall; sys_call_table[__NR_sched_getaffinity] = my_eventSig_syscall; /* A non-zero return means init_module failed; module can't be loaded */ return 0; } /* Restore the preious system calls at rmmod. * Check to see if someone else tried to replace our * system calls while we were loaded. */ void cleanup_module(void) { if ( sys_call_table[__NR_sched_setaffinity] != my_eventWait_syscall || sys_call_table[__NR_sched_getaffinity] != my_eventSig_syscall) { printk(KERN_ALERT "syscall module entry has been corrupted\n"); } /* restore the original syscall entries */ sys_call_table[__NR_sched_setaffinity] = original_call_241; sys_call_table[__NR_sched_getaffinity] = original_call_242; printk(KERN_ALERT "waitOne module unloaded\n"); } MODULE_LICENSE("GPL");