Next Previous Contents

3. ioctls: Not writing a new system call

A system call generally looks like this

        asmlinkage int sys_mycall(int arg) 
        {
                return 0; 
        }

First, in most cases you don't want to create a new system call. You create a character device and implement an appropiate ioctl for it. This is much more flexible than system calls, doesn't have to be entered in every architecture's include/asm/unistd.h and arch/kernel/entry.S file, and is much more likely to be accepted by Linus.

Inside the ioctl you're in user context to a process. When a error occurs you return a negated errno (see include/linux/errno.h), otherwise you return 0.

After you slept you should check if a signal occurred: the Unix/Linux way of handling signals is to temporarily exit the system call with the -ERESTARTSYS error. The system call entry code will switch back to user context, process the signal handler and then your system call will be restarted (unless the user disabled that). So you should be prepared to process the restart, e.g. if you're in the middle of manipulating some data structure.

        if (signal_pending()) 
                return -ERESTARTSYS; 

If you're doing longer computations: first think userspace. If you really want to do it in kernel you should regularly check if you need to give up the CPU (remember there is cooperative multitasking per CPU). Idiom:

        if (current->need_resched)
                schedule(); /* Will sleep */ 

A short note on interface design: the UNIX system call motto is "Provide mechanism not policy"

3.1 Fucking Up Your Box

You cannot call any routines which may sleep, unless:

  1. You are in user context.
  2. You do not own any spinlocks.
  3. You have interrupts enabled (actually, Andi Kleen says that the scheduling code will enable them for you, but that's probably not what you wanted).

You will eventually lock up your box if you break these rules.

Note that some functions may sleep implicitely: common ones are the user space access functions (*_user) and memory allocation functions without GFP_ATOMIC.

Really.


Next Previous Contents