diff --git a/sys/compat/freebsd32/syscalls.master b/sys/compat/freebsd32/syscalls.master index 42e98f2934ea..c6e95503d94a 100644 --- a/sys/compat/freebsd32/syscalls.master +++ b/sys/compat/freebsd32/syscalls.master @@ -604,3 +604,5 @@ 439 UNIMPL extattr_list_link 440 UNIMPL kse_switchin 441 UNIMPL ksem_timedwait +442 MNOPROTO { int thr_suspend(const struct timespec *timeout); } +443 MNOPROTO { int thr_wake(thr_id_t id); } diff --git a/sys/kern/kern_thr.c b/sys/kern/kern_thr.c index eef25acbdf88..24aaaac02751 100644 --- a/sys/kern/kern_thr.c +++ b/sys/kern/kern_thr.c @@ -254,3 +254,64 @@ thr_kill(struct thread *td, struct thr_kill_args *uap) PROC_UNLOCK(p); return (error); } + +int +thr_suspend(struct thread *td, struct thr_suspend_args *uap) + /* const struct timespec *timeout */ +{ + struct timespec ts; + struct timeval tv; + int error; + int hz; + + hz = 0; + error = 0; + if (uap->timeout != NULL) { + error = copyin((const void *)uap->timeout, (void *)&ts, + sizeof(struct timespec)); + if (error != 0) + return (error); + if (ts.tv_nsec < 0 || ts.tv_nsec > 1000000000) + return (EINVAL); + if (ts.tv_sec == 0 && ts.tv_nsec == 0) + return (ETIMEDOUT); + TIMESPEC_TO_TIMEVAL(&tv, &ts); + hz = tvtohz(&tv); + } + PROC_LOCK(td->td_proc); + mtx_lock_spin(&sched_lock); + if ((td->td_flags & TDF_THRWAKEUP) == 0) { + mtx_unlock_spin(&sched_lock); + error = msleep((void *)td, &td->td_proc->p_mtx, + td->td_priority | PCATCH, "lthr", hz); + mtx_lock_spin(&sched_lock); + } + td->td_flags &= ~TDF_THRWAKEUP; + mtx_unlock_spin(&sched_lock); + PROC_UNLOCK(td->td_proc); + return (error == EWOULDBLOCK ? ETIMEDOUT : error); +} + +int +thr_wake(struct thread *td, struct thr_wake_args *uap) + /* thr_id_t id */ +{ + struct thread *tdsleeper, *ttd; + + tdsleeper = ((struct thread *)uap->id); + PROC_LOCK(tdsleeper->td_proc); + FOREACH_THREAD_IN_PROC(tdsleeper->td_proc, ttd) { + if (ttd == tdsleeper) + break; + } + if (ttd == NULL) { + PROC_UNLOCK(tdsleeper->td_proc); + return (ESRCH); + } + mtx_lock_spin(&sched_lock); + tdsleeper->td_flags |= TDF_THRWAKEUP; + mtx_unlock_spin(&sched_lock); + wakeup_one((void *)tdsleeper); + PROC_UNLOCK(tdsleeper->td_proc); + return (0); +} diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master index ceddb974ef15..a5380b6c0af7 100644 --- a/sys/kern/syscalls.master +++ b/sys/kern/syscalls.master @@ -629,5 +629,7 @@ 440 MSTD { int kse_switchin(const struct __mcontext *mcp, \ long val, long *loc); } 441 MNOSTD { int ksem_timedwait(semid_t id, struct timespec *abstime); } +442 MSTD { int thr_suspend(const struct timespec *timeout); } +443 MSTD { int thr_wake(thr_id_t id); } ; Please copy any additions and changes to the following compatability tables: ; sys/compat/freebsd32/syscalls.master diff --git a/sys/sys/proc.h b/sys/sys/proc.h index 0534b87b9230..e067d3cfa601 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -356,6 +356,7 @@ struct thread { #define TDF_NEEDSIGCHK 0x020000 /* Thread may need signal delivery. */ #define TDF_SA 0x040000 /* A scheduler activation based thread. */ #define TDF_UMTXWAKEUP 0x080000 /* Libthr thread must not sleep on a umtx. */ +#define TDF_THRWAKEUP 0x100000 /* Libthr thread must not suspend itself. */ #define TDF_DEADLKTREAT 0x800000 /* Lock aquisition - deadlock treatment. */ /* "private" flags kept in td_pflags */ diff --git a/sys/sys/thr.h b/sys/sys/thr.h index 9869ce3dfeb2..cd0e732f4ff0 100644 --- a/sys/sys/thr.h +++ b/sys/sys/thr.h @@ -46,6 +46,8 @@ int thr_create(ucontext_t *ctx, thr_id_t *id, int flags); int thr_self(thr_id_t *id); void thr_exit(void); int thr_kill(thr_id_t id, int sig); +int thr_suspend(const struct timespec *timeout); +int thr_wake(thr_id_t id); #endif /* !_KERNEL */