On Tue, 29 Sep 1998, Niels Hald Pedersen wrote:

>I would suspect usleep to encapsulate "the SIGALRM method of waiting"
>(set an alarm, sending process a signal after a given time, wait for the
>signal, handle it), at least it has a similar behaviour. I believe I've

usleep simply set the process timeout at the expected time in jiffies and
schedule().  It' s more simple and efficient (also in userspace ;-) than
set an alarm and then pause(). 

>It seems that any waiting time specified is rounded up to something
>being a multiple of 10 ms, and then a handling charge of further 10 ms

This is normal because the timeout set by the kernel before schedule(), is
set in jiffies and jiffies are increased evey 1/HZ sec, where HZ = 100 on
x86. 

If you set the scheduler_policy real time (SCHED_FIFO or SCHED_RR) you' ll
be able to ask for delay < 1/HZ and the kernel will usleep() instead of
schedule(). This is not allowed to process with priority SCHED_OTHERS.
During usleep() the kernel will halt and only irq handlers will be allowed
to run (but don' t expect to see the mouse move because the irq will run
but X not ;-).

Here the interesting piece of code from the kernel tree:

asmlinkage int sys_nanosleep(struct timespec *rqtp, struct timespec *rmtp)
{
        struct timespec t;
        unsigned long expire;

        if(copy_from_user(&t, rqtp, sizeof(struct timespec)))
                return -EFAULT;

        if (t.tv_nsec >= 1000000000L || t.tv_nsec < 0 || t.tv_sec < 0)
                return -EINVAL;


        if (t.tv_sec == 0 && t.tv_nsec <= 2000000L &&
            current->policy != SCHED_OTHER)
        {
                /*
                 * Short delay requests up to 2 ms will be handled with
                 * high precision by a busy wait for all real-time processes.
                 *
                 * Its important on SMP not to do this holding locks.
                 */
                udelay((t.tv_nsec + 999) / 1000);
                return 0;
        }

        expire = timespec_to_jiffies(&t) + (t.tv_sec || t.tv_nsec) + jiffies;

        current->timeout = expire;
        current->state = TASK_INTERRUPTIBLE;
        schedule();

        if (expire > jiffies) {
                if (rmtp) {
                        jiffies_to_timespec(expire - jiffies -
                                            (expire > jiffies + 1), &t);
                        if (copy_to_user(rmtp, &t, sizeof(struct timespec)))
                                return -EFAULT;
                }
                return -EINTR;
        }
        return 0;
}

Andrea[s] Arcangeli

Reply via email to