#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/kthread.h>
#include <sys/ptrace.h>
#include <sys/resourcevar.h>
#include <sys/signalvar.h>
#include <sys/unistd.h>
#include <sys/wait.h>
#include <machine/stdarg.h>
static struct lwkt_token kpsus_token = LWKT_TOKEN_INITIALIZER(kpsus_token);
static int __printflike(6, 0)
_kthread_create(void (*func)(void *), void *arg,
struct thread **tdp, int cpu, bool schedule_now, const char *fmt, __va_list ap)
{
thread_t td;
int flags = 0;
td = lwkt_alloc_thread(NULL, LWKT_THREAD_STACK, cpu, flags);
if (tdp)
*tdp = td;
cpu_set_thread_handler(td, kthread_exit, func, arg);
kvsnprintf(td->td_comm, sizeof(td->td_comm), fmt, ap);
td->td_ucred = crhold(proc0.p_ucred);
if (schedule_now)
lwkt_schedule(td);
return 0;
}
int
kthread_alloc(void (*func)(void *), void *arg,
struct thread **tdp, const char *fmt, ...)
{
__va_list ap;
int ret;
__va_start(ap, fmt);
ret = _kthread_create(func, arg, tdp, -1, false, fmt, ap);
__va_end(ap);
return ret;
}
int
kthread_create(void (*func)(void *), void *arg,
struct thread **tdp, const char *fmt, ...)
{
__va_list ap;
int ret;
__va_start(ap, fmt);
ret = _kthread_create(func, arg, tdp, -1, true, fmt, ap);
__va_end(ap);
return ret;
}
int
kthread_create_cpu(void (*func)(void *), void *arg,
struct thread **tdp, int cpu, const char *fmt, ...)
{
__va_list ap;
int ret;
__va_start(ap, fmt);
ret = _kthread_create(func, arg, tdp, cpu, true, fmt, ap);
__va_end(ap);
return ret;
}
#if 0
int
kthread_create_stk(void (*func)(void *), void *arg,
struct thread **tdp, int stksize, const char *fmt, ...)
{
thread_t td;
__va_list ap;
td = lwkt_alloc_thread(NULL, stksize, -1, 0);
if (tdp)
*tdp = td;
cpu_set_thread_handler(td, kthread_exit, func, arg);
__va_start(ap, fmt);
kvsnprintf(td->td_comm, sizeof(td->td_comm), fmt, ap);
__va_end(ap);
lwkt_schedule(td);
return 0;
}
#endif
void
kthread_exit(void)
{
lwkt_exit();
}
void
kproc_start(const void *udata)
{
const struct kproc_desc *kp = udata;
int error;
error = kthread_create((void (*)(void *))kp->func, NULL,
kp->global_threadpp, "%s", kp->arg0);
lwkt_setpri(*kp->global_threadpp, TDPRI_KERN_DAEMON);
if (error)
panic("kproc_start: %s: error %d", kp->arg0, error);
}
int
suspend_kproc(struct thread *td, int timo)
{
if (td->td_proc == NULL) {
lwkt_gettoken(&kpsus_token);
atomic_set_int(&td->td_mpflags, TDF_MP_STOPREQ);
wakeup(td);
while (td->td_mpflags & TDF_MP_STOPREQ) {
int error = tsleep(td, 0, "suspkp", timo);
if (error == EWOULDBLOCK)
break;
}
atomic_clear_int(&td->td_mpflags, TDF_MP_STOPREQ);
lwkt_reltoken(&kpsus_token);
return(0);
} else {
return(EINVAL);
}
}
void
kproc_suspend_loop(void)
{
struct thread *td = curthread;
if (td->td_mpflags & TDF_MP_STOPREQ) {
lwkt_gettoken(&kpsus_token);
atomic_clear_int(&td->td_mpflags, TDF_MP_STOPREQ);
while ((td->td_mpflags & TDF_MP_WAKEREQ) == 0) {
wakeup(td);
tsleep(td, 0, "kpsusp", 0);
}
atomic_clear_int(&td->td_mpflags, TDF_MP_WAKEREQ);
wakeup(td);
lwkt_reltoken(&kpsus_token);
}
}