Changeset View
Standalone View
sys/kern/kern_time.c
| Show All 26 Lines | |||||||||
| * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||||||||
| * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||||||||
| * SUCH DAMAGE. | * SUCH DAMAGE. | ||||||||
| */ | */ | ||||||||
| #include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||||||
| #include "opt_ktrace.h" | #include "opt_ktrace.h" | ||||||||
| #define EXTERR_CATEGORY EXTERR_CAT_TIME | |||||||||
| #include <sys/param.h> | #include <sys/param.h> | ||||||||
| #include <sys/systm.h> | #include <sys/systm.h> | ||||||||
| #include <sys/limits.h> | #include <sys/limits.h> | ||||||||
| #include <sys/clock.h> | #include <sys/clock.h> | ||||||||
| #include <sys/exterrvar.h> | |||||||||
| #include <sys/lock.h> | #include <sys/lock.h> | ||||||||
| #include <sys/mutex.h> | #include <sys/mutex.h> | ||||||||
| #include <sys/sysproto.h> | #include <sys/sysproto.h> | ||||||||
| #include <sys/resourcevar.h> | #include <sys/resourcevar.h> | ||||||||
| #include <sys/signalvar.h> | #include <sys/signalvar.h> | ||||||||
| #include <sys/kernel.h> | #include <sys/kernel.h> | ||||||||
| #include <sys/sleepqueue.h> | #include <sys/sleepqueue.h> | ||||||||
| #include <sys/syscallsubr.h> | #include <sys/syscallsubr.h> | ||||||||
| ▲ Show 20 Lines • Show All 164 Lines • ▼ Show 20 Lines | case CPUCLOCK_WHICH_PID: | ||||||||
| } | } | ||||||||
| *clk_id = MAKE_PROCESS_CPUCLOCK(pid); | *clk_id = MAKE_PROCESS_CPUCLOCK(pid); | ||||||||
| return (0); | return (0); | ||||||||
| case CPUCLOCK_WHICH_TID: | case CPUCLOCK_WHICH_TID: | ||||||||
| tid = id == 0 ? td->td_tid : id; | tid = id == 0 ? td->td_tid : id; | ||||||||
| *clk_id = MAKE_THREAD_CPUCLOCK(tid); | *clk_id = MAKE_THREAD_CPUCLOCK(tid); | ||||||||
| return (0); | return (0); | ||||||||
| default: | default: | ||||||||
| return (EINVAL); | return (EXTERROR(EINVAL, "Invalid CPUCLOCK_WHICH %jd", which)); | ||||||||
| } | } | ||||||||
| } | } | ||||||||
| #ifndef _SYS_SYSPROTO_H_ | #ifndef _SYS_SYSPROTO_H_ | ||||||||
| struct clock_gettime_args { | struct clock_gettime_args { | ||||||||
| clockid_t clock_id; | clockid_t clock_id; | ||||||||
| struct timespec *tp; | struct timespec *tp; | ||||||||
| }; | }; | ||||||||
| ▲ Show 20 Lines • Show All 67 Lines • ▼ Show 20 Lines | get_cputime(struct thread *td, clockid_t clock_id, struct timespec *ats) | ||||||||
| pid_t pid; | pid_t pid; | ||||||||
| int error; | int error; | ||||||||
| p = td->td_proc; | p = td->td_proc; | ||||||||
| if ((clock_id & CPUCLOCK_PROCESS_BIT) == 0) { | if ((clock_id & CPUCLOCK_PROCESS_BIT) == 0) { | ||||||||
| tid = clock_id & CPUCLOCK_ID_MASK; | tid = clock_id & CPUCLOCK_ID_MASK; | ||||||||
| td2 = tdfind(tid, p->p_pid); | td2 = tdfind(tid, p->p_pid); | ||||||||
| if (td2 == NULL) | if (td2 == NULL) | ||||||||
| return (EINVAL); | return (EXTERROR(EINVAL, "Invalid thread id %jd", | ||||||||
| (intmax_t)tid)); | |||||||||
| kern_thread_cputime(td2, ats); | kern_thread_cputime(td2, ats); | ||||||||
| PROC_UNLOCK(td2->td_proc); | PROC_UNLOCK(td2->td_proc); | ||||||||
| } else { | } else { | ||||||||
| pid = clock_id & CPUCLOCK_ID_MASK; | pid = clock_id & CPUCLOCK_ID_MASK; | ||||||||
| error = pget(pid, PGET_CANSEE, &p2); | error = pget(pid, PGET_CANSEE, &p2); | ||||||||
| if (error != 0) | if (error != 0) | ||||||||
| return (EINVAL); | return (EXTERROR(EINVAL, "Invalid process id %jd", | ||||||||
| (intmax_t)pid)); | |||||||||
| kern_process_cputime(p2, ats); | kern_process_cputime(p2, ats); | ||||||||
| PROC_UNLOCK(p2); | PROC_UNLOCK(p2); | ||||||||
| } | } | ||||||||
| return (0); | return (0); | ||||||||
| } | } | ||||||||
| int | int | ||||||||
| kern_clock_gettime(struct thread *td, clockid_t clock_id, struct timespec *ats) | kern_clock_gettime(struct thread *td, clockid_t clock_id, struct timespec *ats) | ||||||||
| ▲ Show 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | case CLOCK_THREAD_CPUTIME_ID: | ||||||||
| break; | break; | ||||||||
| case CLOCK_PROCESS_CPUTIME_ID: | case CLOCK_PROCESS_CPUTIME_ID: | ||||||||
| PROC_LOCK(p); | PROC_LOCK(p); | ||||||||
| kern_process_cputime(p, ats); | kern_process_cputime(p, ats); | ||||||||
| PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||||||
| break; | break; | ||||||||
| default: | default: | ||||||||
| if ((int)clock_id >= 0) | if ((int)clock_id >= 0) | ||||||||
| return (EINVAL); | return (EXTERROR(EINVAL, "Unknown clock id %jd", | ||||||||
| (intmax_t)clock_id)); | |||||||||
markjUnsubmitted Not Done Inline Actions
markj: | |||||||||
| return (get_cputime(td, clock_id, ats)); | return (get_cputime(td, clock_id, ats)); | ||||||||
| } | } | ||||||||
| return (0); | return (0); | ||||||||
| } | } | ||||||||
| #ifndef _SYS_SYSPROTO_H_ | #ifndef _SYS_SYSPROTO_H_ | ||||||||
| struct clock_settime_args { | struct clock_settime_args { | ||||||||
| clockid_t clock_id; | clockid_t clock_id; | ||||||||
| Show All 21 Lines | |||||||||
| kern_clock_settime(struct thread *td, clockid_t clock_id, struct timespec *ats) | kern_clock_settime(struct thread *td, clockid_t clock_id, struct timespec *ats) | ||||||||
| { | { | ||||||||
| struct timeval atv; | struct timeval atv; | ||||||||
| int error; | int error; | ||||||||
| if ((error = priv_check(td, PRIV_CLOCK_SETTIME)) != 0) | if ((error = priv_check(td, PRIV_CLOCK_SETTIME)) != 0) | ||||||||
| return (error); | return (error); | ||||||||
| if (clock_id != CLOCK_REALTIME) | if (clock_id != CLOCK_REALTIME) | ||||||||
| return (EINVAL); | return (EXTERROR(EINVAL, "clock_id %jd not CLOCK_REALTIME", | ||||||||
| (intmax_t)clock_id)); | |||||||||
| if (!timespecvalid_interval(ats)) | if (!timespecvalid_interval(ats)) | ||||||||
| return (EINVAL); | return (EXTERROR(EINVAL, "Invalid timespec")); | ||||||||
| if (!allow_insane_settime && | if (!allow_insane_settime && | ||||||||
| (ats->tv_sec > 8000ULL * 365 * 24 * 60 * 60 || | (ats->tv_sec > 8000ULL * 365 * 24 * 60 * 60 || | ||||||||
| ats->tv_sec < utc_offset())) | ats->tv_sec < utc_offset())) | ||||||||
| return (EINVAL); | return (EXTERROR(EINVAL, "Insane clock jump")); | ||||||||
Not Done Inline Actions
markj: | |||||||||
Not Done Inline ActionsSuggest being more specific: if (!timespecvalid_interval(ats)) {
if (ats->tv_sec < 0)
return (EXTERROR(EINVAL, "Backward clock jump"));
return (EXTERROR(EINVAL, "Out of range tv_nsec %jd",
ats->tv_nsec));
}mckusick: Suggest being more specific:
```
if (!timespecvalid_interval(ats)) {… | |||||||||
| /* XXX Don't convert nsec->usec and back */ | /* XXX Don't convert nsec->usec and back */ | ||||||||
| TIMESPEC_TO_TIMEVAL(&atv, ats); | TIMESPEC_TO_TIMEVAL(&atv, ats); | ||||||||
| error = settime(td, &atv); | error = settime(td, &atv); | ||||||||
| return (error); | return (error); | ||||||||
| } | } | ||||||||
| #ifndef _SYS_SYSPROTO_H_ | #ifndef _SYS_SYSPROTO_H_ | ||||||||
| struct clock_getres_args { | struct clock_getres_args { | ||||||||
| ▲ Show 20 Lines • Show All 51 Lines • ▼ Show 20 Lines | kern_clock_getres(struct thread *td, clockid_t clock_id, struct timespec *ts) | ||||||||
| case CLOCK_THREAD_CPUTIME_ID: | case CLOCK_THREAD_CPUTIME_ID: | ||||||||
| case CLOCK_PROCESS_CPUTIME_ID: | case CLOCK_PROCESS_CPUTIME_ID: | ||||||||
| cputime: | cputime: | ||||||||
| ts->tv_nsec = 1000000000 / cpu_tickrate() + 1; | ts->tv_nsec = 1000000000 / cpu_tickrate() + 1; | ||||||||
| break; | break; | ||||||||
| default: | default: | ||||||||
| if ((int)clock_id < 0) | if ((int)clock_id < 0) | ||||||||
| goto cputime; | goto cputime; | ||||||||
| return (EINVAL); | return (EXTERROR(EINVAL, "clock_id %jd invalid", | ||||||||
| (intmax_t)clock_id)); | |||||||||
| } | } | ||||||||
| return (0); | return (0); | ||||||||
| } | } | ||||||||
| int | int | ||||||||
| kern_nanosleep(struct thread *td, struct timespec *rqt, struct timespec *rmt) | kern_nanosleep(struct thread *td, struct timespec *rqt, struct timespec *rmt) | ||||||||
| { | { | ||||||||
| Show All 13 Lines | |||||||||
| { | { | ||||||||
| struct timespec ts, now; | struct timespec ts, now; | ||||||||
| sbintime_t sbt, sbtt, prec, tmp; | sbintime_t sbt, sbtt, prec, tmp; | ||||||||
| time_t over; | time_t over; | ||||||||
| int error; | int error; | ||||||||
| bool is_abs_real, precise; | bool is_abs_real, precise; | ||||||||
| if (rqt->tv_nsec < 0 || rqt->tv_nsec >= NS_PER_SEC) | if (rqt->tv_nsec < 0 || rqt->tv_nsec >= NS_PER_SEC) | ||||||||
| return (EINVAL); | return (EXTERROR(EINVAL, "rqt bad nanosecond %jd", | ||||||||
| (intmax_t)rqt->tv_nsec)); | |||||||||
| if ((flags & ~TIMER_ABSTIME) != 0) | if ((flags & ~TIMER_ABSTIME) != 0) | ||||||||
| return (EINVAL); | return (EXTERROR(EINVAL, "Bad timer flags set %#x", flags)); | ||||||||
Not Done Inline Actions
In fact all cases could benefit from providing the wrong value that triggered the EINVAL, but this is optional. kib: In fact all cases could benefit from providing the wrong value that triggered the EINVAL, but… | |||||||||
| switch (clock_id) { | switch (clock_id) { | ||||||||
| case CLOCK_REALTIME: | case CLOCK_REALTIME: | ||||||||
| case CLOCK_TAI: | case CLOCK_TAI: | ||||||||
| precise = nanosleep_precise; | precise = nanosleep_precise; | ||||||||
| is_abs_real = (flags & TIMER_ABSTIME) != 0; | is_abs_real = (flags & TIMER_ABSTIME) != 0; | ||||||||
| break; | break; | ||||||||
| case CLOCK_REALTIME_PRECISE: | case CLOCK_REALTIME_PRECISE: | ||||||||
| precise = true; | precise = true; | ||||||||
| Show All 20 Lines | case CLOCK_UPTIME_FAST: | ||||||||
| is_abs_real = false; | is_abs_real = false; | ||||||||
| break; | break; | ||||||||
| case CLOCK_VIRTUAL: | case CLOCK_VIRTUAL: | ||||||||
| case CLOCK_PROF: | case CLOCK_PROF: | ||||||||
| case CLOCK_PROCESS_CPUTIME_ID: | case CLOCK_PROCESS_CPUTIME_ID: | ||||||||
| return (ENOTSUP); | return (ENOTSUP); | ||||||||
| case CLOCK_THREAD_CPUTIME_ID: | case CLOCK_THREAD_CPUTIME_ID: | ||||||||
| default: | default: | ||||||||
| return (EINVAL); | return (EXTERROR(EINVAL, "clock_id %jd invalid", | ||||||||
| (intmax_t)clock_id)); | |||||||||
| } | } | ||||||||
| do { | do { | ||||||||
| ts = *rqt; | ts = *rqt; | ||||||||
| if ((flags & TIMER_ABSTIME) != 0) { | if ((flags & TIMER_ABSTIME) != 0) { | ||||||||
| if (is_abs_real) | if (is_abs_real) | ||||||||
| td->td_rtcgen = | td->td_rtcgen = | ||||||||
| atomic_load_acq_int(&rtc_generation); | atomic_load_acq_int(&rtc_generation); | ||||||||
| error = kern_clock_gettime(td, clock_id, &now); | error = kern_clock_gettime(td, clock_id, &now); | ||||||||
| ▲ Show 20 Lines • Show All 164 Lines • ▼ Show 20 Lines | kern_settimeofday(struct thread *td, struct timeval *tv, struct timezone *tzp) | ||||||||
| error = priv_check(td, PRIV_SETTIMEOFDAY); | error = priv_check(td, PRIV_SETTIMEOFDAY); | ||||||||
| if (error) | if (error) | ||||||||
| return (error); | return (error); | ||||||||
| /* Verify all parameters before changing time. */ | /* Verify all parameters before changing time. */ | ||||||||
| if (tv) { | if (tv) { | ||||||||
| if (tv->tv_usec < 0 || tv->tv_usec >= 1000000 || | if (tv->tv_usec < 0 || tv->tv_usec >= 1000000 || | ||||||||
| tv->tv_sec < 0) | tv->tv_sec < 0) | ||||||||
| return (EINVAL); | return (EXTERROR(EINVAL, "Bad timeval %jd %jd", | ||||||||
| (intmax_t)tv->tv_sec, (intmax_t)tv->tv_usec)); | |||||||||
| error = settime(td, tv); | error = settime(td, tv); | ||||||||
| } | } | ||||||||
| return (error); | return (error); | ||||||||
| } | } | ||||||||
| /* | /* | ||||||||
| * Get value of an interval timer. The process virtual and profiling virtual | * Get value of an interval timer. The process virtual and profiling virtual | ||||||||
| * time timers are kept in the p_stats area, since they can be swapped out. | * time timers are kept in the p_stats area, since they can be swapped out. | ||||||||
| Show All 35 Lines | |||||||||
| int | int | ||||||||
| kern_getitimer(struct thread *td, u_int which, struct itimerval *aitv) | kern_getitimer(struct thread *td, u_int which, struct itimerval *aitv) | ||||||||
| { | { | ||||||||
| struct proc *p = td->td_proc; | struct proc *p = td->td_proc; | ||||||||
| struct timeval ctv; | struct timeval ctv; | ||||||||
| if (which > ITIMER_PROF) | if (which > ITIMER_PROF) | ||||||||
| return (EINVAL); | return (EXTERROR(EINVAL, "Invalid itimer type %u", which)); | ||||||||
kibUnsubmitted Not Done Inline ActionsThe format needs to be %ju. I.e. all format specifiers must be for (u)intmax_t. On the other hand, I do not think that the casts of the arguments to intmax are needed. kib: The format needs to be %ju. I.e. all format specifiers must be for (u)intmax_t. On the other… | |||||||||
impAuthorUnsubmitted Done Inline ActionsOK. I'm super confused about how that could possibly work. Why aren't the casts needed, and why does this have to be %ju? I missed something, somewhere I think. imp: OK. I'm super confused about how that could possibly work. Why aren't the casts needed, and why… | |||||||||
kibUnsubmitted Not Done Inline ActionsThe format string and the arguments are copied intact from kernel to usermode. Usermode, libc specifically, does the formatting. Arguments are marshaled through uint64_t objects, and are cast to uintmax_t for the formatting. This is done so no memory allocation happens in kernel on error, so that EXTERROR() works in almost any context that has a valid struct thread. kib: The format string and the arguments are copied intact from kernel to usermode. Usermode, libc… | |||||||||
kibUnsubmitted Not Done Inline ActionsIt is documented in exterror(9) kib: It is documented in exterror(9) | |||||||||
| if (which == ITIMER_REAL) { | if (which == ITIMER_REAL) { | ||||||||
| /* | /* | ||||||||
| * Convert from absolute to relative time in .it_value | * Convert from absolute to relative time in .it_value | ||||||||
| * part of real time timer. If time for real time timer | * part of real time timer. If time for real time timer | ||||||||
| * has passed return 0, else return difference between | * has passed return 0, else return difference between | ||||||||
| * current time and time for the timer to go off. | * current time and time for the timer to go off. | ||||||||
| */ | */ | ||||||||
| ▲ Show 20 Lines • Show All 51 Lines • ▼ Show 20 Lines | kern_setitimer(struct thread *td, u_int which, struct itimerval *aitv, | ||||||||
| struct proc *p = td->td_proc; | struct proc *p = td->td_proc; | ||||||||
| struct timeval ctv; | struct timeval ctv; | ||||||||
| sbintime_t sbt, pr; | sbintime_t sbt, pr; | ||||||||
| if (aitv == NULL) | if (aitv == NULL) | ||||||||
| return (kern_getitimer(td, which, oitv)); | return (kern_getitimer(td, which, oitv)); | ||||||||
| if (which > ITIMER_PROF) | if (which > ITIMER_PROF) | ||||||||
| return (EINVAL); | return (EXTERROR(EINVAL, "Invalid itimer type %u", which)); | ||||||||
| #ifdef KTRACE | #ifdef KTRACE | ||||||||
| if (KTRPOINT(td, KTR_STRUCT)) | if (KTRPOINT(td, KTR_STRUCT)) | ||||||||
| ktritimerval(aitv); | ktritimerval(aitv); | ||||||||
| #endif | #endif | ||||||||
| if (itimerfix(&aitv->it_value) || | if (itimerfix(&aitv->it_value) || | ||||||||
| aitv->it_value.tv_sec > INT32_MAX / 2) | aitv->it_value.tv_sec > INT32_MAX / 2) | ||||||||
| return (EINVAL); | return (EXTERROR(EINVAL, "Interval too large %jd", | ||||||||
| (intmax_t)aitv->it_value.tv_sec)); | |||||||||
| if (!timevalisset(&aitv->it_value)) | if (!timevalisset(&aitv->it_value)) | ||||||||
| timevalclear(&aitv->it_interval); | timevalclear(&aitv->it_interval); | ||||||||
| else if (itimerfix(&aitv->it_interval) || | else if (itimerfix(&aitv->it_interval) || | ||||||||
| aitv->it_interval.tv_sec > INT32_MAX / 2) | aitv->it_interval.tv_sec > INT32_MAX / 2) | ||||||||
| return (EINVAL); | return (EXTERROR(EINVAL, | ||||||||
| "Interval too large for existing timer %jd", | |||||||||
| (intmax_t)aitv->it_interval.tv_sec)); | |||||||||
| if (which == ITIMER_REAL) { | if (which == ITIMER_REAL) { | ||||||||
| PROC_LOCK(p); | PROC_LOCK(p); | ||||||||
| if (timevalisset(&p->p_realtimer.it_value)) | if (timevalisset(&p->p_realtimer.it_value)) | ||||||||
| callout_stop(&p->p_itcallout); | callout_stop(&p->p_itcallout); | ||||||||
| microuptime(&ctv); | microuptime(&ctv); | ||||||||
| if (timevalisset(&aitv->it_value)) { | if (timevalisset(&aitv->it_value)) { | ||||||||
| pr = tvtosbt(aitv->it_value) >> tc_precexp; | pr = tvtosbt(aitv->it_value) >> tc_precexp; | ||||||||
| ▲ Show 20 Lines • Show All 390 Lines • ▼ Show 20 Lines | kern_ktimer_create(struct thread *td, clockid_t clock_id, struct sigevent *evp, | ||||||||
| int *timerid, int preset_id) | int *timerid, int preset_id) | ||||||||
| { | { | ||||||||
| struct proc *p = td->td_proc; | struct proc *p = td->td_proc; | ||||||||
| struct itimer *it; | struct itimer *it; | ||||||||
| int id; | int id; | ||||||||
| int error; | int error; | ||||||||
| if (clock_id < 0 || clock_id >= MAX_CLOCKS) | if (clock_id < 0 || clock_id >= MAX_CLOCKS) | ||||||||
| return (EINVAL); | return (EXTERROR(EINVAL, "Invalid clock_id %jd", | ||||||||
| (intmax_t)clock_id)); | |||||||||
Not Done Inline ActionsThis is spelled "clock_id invalid" elsewhere. markj: This is spelled "clock_id invalid" elsewhere. | |||||||||
| if (posix_clocks[clock_id].timer_create == NULL) | if (posix_clocks[clock_id].timer_create == NULL) | ||||||||
| return (EINVAL); | return (EXTERROR(EINVAL, "Null posix clock %jd", | ||||||||
| (intmax_t)clock_id)); | |||||||||
| if (evp != NULL) { | if (evp != NULL) { | ||||||||
| if (evp->sigev_notify != SIGEV_NONE && | if (evp->sigev_notify != SIGEV_NONE && | ||||||||
| evp->sigev_notify != SIGEV_SIGNAL && | evp->sigev_notify != SIGEV_SIGNAL && | ||||||||
| evp->sigev_notify != SIGEV_THREAD_ID) | evp->sigev_notify != SIGEV_THREAD_ID) | ||||||||
| return (EINVAL); | return (EXTERROR(EINVAL, "sigev_notify invalid %d", | ||||||||
| evp->sigev_notify)); | |||||||||
| if ((evp->sigev_notify == SIGEV_SIGNAL || | if ((evp->sigev_notify == SIGEV_SIGNAL || | ||||||||
| evp->sigev_notify == SIGEV_THREAD_ID) && | evp->sigev_notify == SIGEV_THREAD_ID) && | ||||||||
| !_SIG_VALID(evp->sigev_signo)) | !_SIG_VALID(evp->sigev_signo)) | ||||||||
| return (EINVAL); | return (EXTERROR(EINVAL, "signal number invalid %d", | ||||||||
| evp->sigev_notify)); | |||||||||
| } | } | ||||||||
| if (p->p_itimers == NULL) | if (p->p_itimers == NULL) | ||||||||
| itimers_alloc(p); | itimers_alloc(p); | ||||||||
| it = uma_zalloc(itimer_zone, M_WAITOK); | it = uma_zalloc(itimer_zone, M_WAITOK); | ||||||||
| it->it_flags = 0; | it->it_flags = 0; | ||||||||
| it->it_usecount = 0; | it->it_usecount = 0; | ||||||||
| ▲ Show 20 Lines • Show All 108 Lines • ▼ Show 20 Lines | |||||||||
| { | { | ||||||||
| struct proc *p = td->td_proc; | struct proc *p = td->td_proc; | ||||||||
| struct itimer *it; | struct itimer *it; | ||||||||
| PROC_LOCK(p); | PROC_LOCK(p); | ||||||||
| it = itimer_find(p, timerid); | it = itimer_find(p, timerid); | ||||||||
| if (it == NULL) { | if (it == NULL) { | ||||||||
| PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||||||
| return (EINVAL); | return (EXTERROR(EINVAL, "No itimer found id %d", timerid)); | ||||||||
| } | } | ||||||||
| PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||||||
| it->it_flags |= ITF_DELETING; | it->it_flags |= ITF_DELETING; | ||||||||
| while (it->it_usecount > 0) { | while (it->it_usecount > 0) { | ||||||||
| it->it_flags |= ITF_WANTED; | it->it_flags |= ITF_WANTED; | ||||||||
| msleep(it, &it->it_mtx, PPAUSE, "itimer", 0); | msleep(it, &it->it_mtx, PPAUSE, "itimer", 0); | ||||||||
| } | } | ||||||||
| ▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | kern_ktimer_settime(struct thread *td, int timer_id, int flags, | ||||||||
| struct proc *p; | struct proc *p; | ||||||||
| struct itimer *it; | struct itimer *it; | ||||||||
| int error; | int error; | ||||||||
| p = td->td_proc; | p = td->td_proc; | ||||||||
| PROC_LOCK(p); | PROC_LOCK(p); | ||||||||
| if (timer_id < 3 || (it = itimer_find(p, timer_id)) == NULL) { | if (timer_id < 3 || (it = itimer_find(p, timer_id)) == NULL) { | ||||||||
| PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||||||
| error = EINVAL; | error = EXTERROR(EINVAL, "No itimer found %d", timer_id); | ||||||||
| } else { | } else { | ||||||||
| PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||||||
| itimer_enter(it); | itimer_enter(it); | ||||||||
| error = CLOCK_CALL(it->it_clockid, timer_settime, (it, | error = CLOCK_CALL(it->it_clockid, timer_settime, (it, | ||||||||
| flags, val, oval)); | flags, val, oval)); | ||||||||
| itimer_leave(it); | itimer_leave(it); | ||||||||
| ITIMER_UNLOCK(it); | ITIMER_UNLOCK(it); | ||||||||
| } | } | ||||||||
| Show All 24 Lines | kern_ktimer_gettime(struct thread *td, int timer_id, struct itimerspec *val) | ||||||||
| struct proc *p; | struct proc *p; | ||||||||
| struct itimer *it; | struct itimer *it; | ||||||||
| int error; | int error; | ||||||||
| p = td->td_proc; | p = td->td_proc; | ||||||||
| PROC_LOCK(p); | PROC_LOCK(p); | ||||||||
| if (timer_id < 3 || (it = itimer_find(p, timer_id)) == NULL) { | if (timer_id < 3 || (it = itimer_find(p, timer_id)) == NULL) { | ||||||||
| PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||||||
| error = EINVAL; | error = EXTERROR(EINVAL, "No itimer found %d", timer_id); | ||||||||
| } else { | } else { | ||||||||
| PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||||||
| itimer_enter(it); | itimer_enter(it); | ||||||||
| error = CLOCK_CALL(it->it_clockid, timer_gettime, (it, val)); | error = CLOCK_CALL(it->it_clockid, timer_gettime, (it, val)); | ||||||||
| itimer_leave(it); | itimer_leave(it); | ||||||||
| ITIMER_UNLOCK(it); | ITIMER_UNLOCK(it); | ||||||||
| } | } | ||||||||
| return (error); | return (error); | ||||||||
| Show All 17 Lines | kern_ktimer_getoverrun(struct thread *td, int timer_id) | ||||||||
| struct proc *p = td->td_proc; | struct proc *p = td->td_proc; | ||||||||
| struct itimer *it; | struct itimer *it; | ||||||||
| int error ; | int error ; | ||||||||
| PROC_LOCK(p); | PROC_LOCK(p); | ||||||||
| if (timer_id < 3 || | if (timer_id < 3 || | ||||||||
| (it = itimer_find(p, timer_id)) == NULL) { | (it = itimer_find(p, timer_id)) == NULL) { | ||||||||
| PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||||||
| error = EINVAL; | error = EXTERROR(EINVAL, "No itimer found %d", timer_id); | ||||||||
| } else { | } else { | ||||||||
| td->td_retval[0] = it->it_overrun_last; | td->td_retval[0] = it->it_overrun_last; | ||||||||
| ITIMER_UNLOCK(it); | ITIMER_UNLOCK(it); | ||||||||
| PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||||||
| error = 0; | error = 0; | ||||||||
| } | } | ||||||||
| return (error); | return (error); | ||||||||
| } | } | ||||||||
| ▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | realtimer_settime(struct itimer *it, int flags, struct itimerspec *value, | ||||||||
| struct timeval tv; | struct timeval tv; | ||||||||
| struct itimerspec val; | struct itimerspec val; | ||||||||
| int error; | int error; | ||||||||
| mtx_assert(&it->it_mtx, MA_OWNED); | mtx_assert(&it->it_mtx, MA_OWNED); | ||||||||
| val = *value; | val = *value; | ||||||||
| if (itimespecfix(&val.it_value)) | if (itimespecfix(&val.it_value)) | ||||||||
| return (EINVAL); | return (EXTERROR(EINVAL, "Cannot fix itimer")); | ||||||||
| if (timespecisset(&val.it_value)) { | if (timespecisset(&val.it_value)) { | ||||||||
| if (itimespecfix(&val.it_interval)) | if (itimespecfix(&val.it_interval)) | ||||||||
| return (EINVAL); | return (EXTERROR(EINVAL, "Cannot fix interval")); | ||||||||
| } else { | } else { | ||||||||
| timespecclear(&val.it_interval); | timespecclear(&val.it_interval); | ||||||||
| } | } | ||||||||
| if (ovalue != NULL) | if (ovalue != NULL) | ||||||||
| realtimer_gettime(it, ovalue); | realtimer_gettime(it, ovalue); | ||||||||
| it->it_time = val; | it->it_time = val; | ||||||||
| ▲ Show 20 Lines • Show All 238 Lines • Show Last 20 Lines | |||||||||