X-Git-Url: https://gitweb.dragonflybsd.org/dragonfly.git/blobdiff_plain/684a93c4b15cf9f678dcf209702dadcd4f670406..4643740aa6f3eac7d3dfab05967ec55b5d8ba984:/sys/kern/kern_time.c diff --git a/sys/kern/kern_time.c b/sys/kern/kern_time.c index 2f3ec8488f..3058bf043a 100644 --- a/sys/kern/kern_time.c +++ b/sys/kern/kern_time.c @@ -32,7 +32,6 @@ * * @(#)kern_time.c 8.1 (Berkeley) 6/10/93 * $FreeBSD: src/sys/kern/kern_time.c,v 1.68.2.1 2002/10/01 08:00:41 bde Exp $ - * $DragonFly: src/sys/kern/kern_time.c,v 1.40 2008/04/02 14:16:16 sephe Exp $ */ #include @@ -42,7 +41,6 @@ #include #include #include -#include #include #include #include @@ -70,12 +68,24 @@ struct timezone tz; * timers when they expire. */ -static int nanosleep1(struct timespec *rqt, struct timespec *rmt); static int settime(struct timeval *); static void timevalfix(struct timeval *); -static int sleep_hard_us = 100; -SYSCTL_INT(_kern, OID_AUTO, sleep_hard_us, CTLFLAG_RW, &sleep_hard_us, 0, "") +/* + * Nanosleep tries very hard to sleep for a precisely requested time + * interval, down to 1uS. The administrator can impose a minimum delay + * and a delay below which we hard-loop instead of initiate a timer + * interrupt and sleep. + * + * For machines under high loads it might be beneficial to increase min_us + * to e.g. 1000uS (1ms) so spining processes sleep meaningfully. + */ +static int nanosleep_min_us = 10; +static int nanosleep_hard_us = 100; +SYSCTL_INT(_kern, OID_AUTO, nanosleep_min_us, CTLFLAG_RW, + &nanosleep_min_us, 0, "") +SYSCTL_INT(_kern, OID_AUTO, nanosleep_hard_us, CTLFLAG_RW, + &nanosleep_hard_us, 0, "") static int settime(struct timeval *tv) @@ -284,40 +294,42 @@ sys_clock_getres(struct clock_getres_args *uap) * MPSAFE */ static void -ns1_systimer(systimer_t info) +ns1_systimer(systimer_t info, int in_ipi __unused, + struct intrframe *frame __unused) { lwkt_schedule(info->data); } -static int +int nanosleep1(struct timespec *rqt, struct timespec *rmt) { static int nanowait; struct timespec ts, ts2, ts3; struct timeval tv; int error; - int tried_yield; if (rqt->tv_nsec < 0 || rqt->tv_nsec >= 1000000000) return (EINVAL); + /* XXX: imho this should return EINVAL at least for tv_sec < 0 */ if (rqt->tv_sec < 0 || (rqt->tv_sec == 0 && rqt->tv_nsec == 0)) return (0); nanouptime(&ts); timespecadd(&ts, rqt); /* ts = target timestamp compare */ TIMESPEC_TO_TIMEVAL(&tv, rqt); /* tv = sleep interval */ - tried_yield = 0; for (;;) { int ticks; struct systimer info; - ticks = tv.tv_usec / tick; /* approximate */ + ticks = tv.tv_usec / ustick; /* approximate */ if (tv.tv_sec == 0 && ticks == 0) { thread_t td = curthread; - if (tried_yield || tv.tv_usec < sleep_hard_us) { - tried_yield = 0; - uio_yield(); + if (tv.tv_usec > 0 && tv.tv_usec < nanosleep_min_us) + tv.tv_usec = nanosleep_min_us; + if (tv.tv_usec < nanosleep_hard_us) { + lwkt_user_yield(); + cpu_pause(); } else { crit_enter_quick(td); systimer_init_oneshot(&info, ns1_systimer, @@ -692,8 +704,7 @@ sys_getitimer(struct getitimer_args *uap) if (uap->which > ITIMER_PROF) return (EINVAL); - get_mplock(); - crit_enter(); + lwkt_gettoken(&p->p_token); if (uap->which == ITIMER_REAL) { /* * Convert from absolute to relative time in .it_value @@ -712,8 +723,7 @@ sys_getitimer(struct getitimer_args *uap) } else { aitv = p->p_timer[uap->which]; } - crit_exit(); - rel_mplock(); + lwkt_reltoken(&p->p_token); return (copyout(&aitv, uap->itv, sizeof (struct itimerval))); } @@ -746,8 +756,7 @@ sys_setitimer(struct setitimer_args *uap) timevalclear(&aitv.it_interval); else if (itimerfix(&aitv.it_interval)) return (EINVAL); - get_mplock(); - crit_enter(); + lwkt_gettoken(&p->p_token); if (uap->which == ITIMER_REAL) { if (timevalisset(&p->p_realtimer.it_value)) callout_stop(&p->p_ithandle); @@ -759,9 +768,16 @@ sys_setitimer(struct setitimer_args *uap) p->p_realtimer = aitv; } else { p->p_timer[uap->which] = aitv; + switch(uap->which) { + case ITIMER_VIRTUAL: + p->p_flags &= ~P_SIGVTALRM; + break; + case ITIMER_PROF: + p->p_flags &= ~P_SIGPROF; + break; + } } - crit_exit(); - rel_mplock(); + lwkt_reltoken(&p->p_token); return (0); } @@ -784,26 +800,27 @@ realitexpire(void *arg) struct timeval ctv, ntv; p = (struct proc *)arg; + lwkt_gettoken(&p->p_token); ksignal(p, SIGALRM); if (!timevalisset(&p->p_realtimer.it_interval)) { timevalclear(&p->p_realtimer.it_value); + lwkt_reltoken(&p->p_token); return; } for (;;) { - crit_enter(); timevaladd(&p->p_realtimer.it_value, - &p->p_realtimer.it_interval); + &p->p_realtimer.it_interval); getmicrouptime(&ctv); if (timevalcmp(&p->p_realtimer.it_value, &ctv, >)) { ntv = p->p_realtimer.it_value; timevalsub(&ntv, &ctv); callout_reset(&p->p_ithandle, tvtohz_low(&ntv), realitexpire, p); - crit_exit(); + lwkt_reltoken(&p->p_token); return; } - crit_exit(); } + lwkt_reltoken(&p->p_token); } /* @@ -821,8 +838,8 @@ itimerfix(struct timeval *tv) if (tv->tv_sec < 0 || tv->tv_sec > 100000000 || tv->tv_usec < 0 || tv->tv_usec >= 1000000) return (EINVAL); - if (tv->tv_sec == 0 && tv->tv_usec != 0 && tv->tv_usec < tick) - tv->tv_usec = tick; + if (tv->tv_sec == 0 && tv->tv_usec != 0 && tv->tv_usec < ustick) + tv->tv_usec = ustick; return (0); }