#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/proc.h>
#include <sys/rtprio.h>
#include <sys/queue.h>
#include <sys/sysctl.h>
#include <sys/kthread.h>
#include <sys/signalvar.h>
#include <sys/signal2.h>
#include <machine/cpu.h>
#include <sys/lock.h>
#include <vm/vm.h>
#include <vm/vm_param.h>
#include <vm/vm_kern.h>
#include <vm/vm_object.h>
#include <vm/vm_page.h>
#include <vm/vm_map.h>
#include <vm/vm_pager.h>
#include <vm/vm_extern.h>
#include <vm/vm_zone.h>
#include <sys/thread2.h>
#include <sys/msgport2.h>
#include <sys/spinlock2.h>
#include <sys/serialize.h>
#include <machine/stdarg.h>
#include <machine/cpufunc.h>
#include <machine/smp.h>
#include <sys/malloc.h>
MALLOC_DEFINE(M_LWKTMSG, "lwkt message", "lwkt message");
static __inline int
lwkt_beginmsg(lwkt_port_t port, lwkt_msg_t msg)
{
return port->mp_putport(port, msg);
}
static __inline int
lwkt_beginmsg_oncpu(lwkt_port_t port, lwkt_msg_t msg)
{
return port->mp_putport_oncpu(port, msg);
}
static __inline void
_lwkt_sendmsg_prepare(lwkt_port_t port, lwkt_msg_t msg)
{
KKASSERT(msg->ms_reply_port != NULL &&
(msg->ms_flags & (MSGF_DONE|MSGF_QUEUED)) == MSGF_DONE);
msg->ms_flags &= ~(MSGF_REPLY | MSGF_SYNC | MSGF_DONE);
}
static __inline void
_lwkt_sendmsg_start(lwkt_port_t port, lwkt_msg_t msg)
{
int error;
if ((error = lwkt_beginmsg(port, msg)) != EASYNC) {
lwkt_replymsg(msg, error);
}
}
static __inline void
_lwkt_sendmsg_start_oncpu(lwkt_port_t port, lwkt_msg_t msg)
{
int error;
if ((error = lwkt_beginmsg_oncpu(port, msg)) != EASYNC) {
lwkt_replymsg(msg, error);
}
}
void
lwkt_sendmsg(lwkt_port_t port, lwkt_msg_t msg)
{
_lwkt_sendmsg_prepare(port, msg);
_lwkt_sendmsg_start(port, msg);
}
void
lwkt_sendmsg_oncpu(lwkt_port_t port, lwkt_msg_t msg)
{
_lwkt_sendmsg_prepare(port, msg);
_lwkt_sendmsg_start_oncpu(port, msg);
}
void
lwkt_sendmsg_prepare(lwkt_port_t port, lwkt_msg_t msg)
{
_lwkt_sendmsg_prepare(port, msg);
}
void
lwkt_sendmsg_start(lwkt_port_t port, lwkt_msg_t msg)
{
_lwkt_sendmsg_start(port, msg);
}
void
lwkt_sendmsg_start_oncpu(lwkt_port_t port, lwkt_msg_t msg)
{
_lwkt_sendmsg_start_oncpu(port, msg);
}
int
lwkt_domsg(lwkt_port_t port, lwkt_msg_t msg, int flags)
{
int error;
KKASSERT(msg->ms_reply_port != NULL &&
(msg->ms_flags & (MSGF_DONE|MSGF_QUEUED)) == MSGF_DONE);
msg->ms_flags &= ~(MSGF_REPLY | MSGF_DONE);
msg->ms_flags |= MSGF_SYNC;
if ((error = lwkt_beginmsg(port, msg)) == EASYNC) {
error = lwkt_waitmsg(msg, flags);
} else {
msg->ms_flags |= MSGF_DONE | MSGF_REPLY;
}
return(error);
}
int
lwkt_forwardmsg(lwkt_port_t port, lwkt_msg_t msg)
{
int error;
KKASSERT((msg->ms_flags & (MSGF_QUEUED|MSGF_DONE|MSGF_REPLY)) == 0);
if ((error = port->mp_putport(port, msg)) != EASYNC)
lwkt_replymsg(msg, error);
return(error);
}
void
lwkt_abortmsg(lwkt_msg_t msg)
{
crit_enter();
if (msg->ms_flags & MSGF_ABORTABLE) {
if ((msg->ms_flags & (MSGF_DONE|MSGF_REPLY)) == 0)
msg->ms_abortfn(msg);
}
crit_exit();
}
static void *lwkt_thread_getport(lwkt_port_t port);
static int lwkt_thread_putport(lwkt_port_t port, lwkt_msg_t msg);
static int lwkt_thread_waitmsg(lwkt_msg_t msg, int flags);
static void *lwkt_thread_waitport(lwkt_port_t port, int flags);
static void lwkt_thread_replyport(lwkt_port_t port, lwkt_msg_t msg);
static int lwkt_thread_dropmsg(lwkt_port_t port, lwkt_msg_t msg);
static void *lwkt_spin_getport(lwkt_port_t port);
static int lwkt_spin_putport(lwkt_port_t port, lwkt_msg_t msg);
static int lwkt_spin_waitmsg(lwkt_msg_t msg, int flags);
static void *lwkt_spin_waitport(lwkt_port_t port, int flags);
static void lwkt_spin_replyport(lwkt_port_t port, lwkt_msg_t msg);
static int lwkt_spin_dropmsg(lwkt_port_t port, lwkt_msg_t msg);
static int lwkt_spin_putport_oncpu(lwkt_port_t port, lwkt_msg_t msg);
static void *lwkt_serialize_getport(lwkt_port_t port);
static int lwkt_serialize_putport(lwkt_port_t port, lwkt_msg_t msg);
static int lwkt_serialize_waitmsg(lwkt_msg_t msg, int flags);
static void *lwkt_serialize_waitport(lwkt_port_t port, int flags);
static void lwkt_serialize_replyport(lwkt_port_t port, lwkt_msg_t msg);
static void lwkt_null_replyport(lwkt_port_t port, lwkt_msg_t msg);
static void *lwkt_panic_getport(lwkt_port_t port);
static int lwkt_panic_putport(lwkt_port_t port, lwkt_msg_t msg);
static int lwkt_panic_waitmsg(lwkt_msg_t msg, int flags);
static void *lwkt_panic_waitport(lwkt_port_t port, int flags);
static void lwkt_panic_replyport(lwkt_port_t port, lwkt_msg_t msg);
static int lwkt_panic_dropmsg(lwkt_port_t port, lwkt_msg_t msg);
static int lwkt_panic_putport_oncpu(lwkt_port_t port, lwkt_msg_t msg);
static __inline
void
_lwkt_initport(lwkt_port_t port,
void *(*gportfn)(lwkt_port_t),
int (*pportfn)(lwkt_port_t, lwkt_msg_t),
int (*wmsgfn)(lwkt_msg_t, int),
void *(*wportfn)(lwkt_port_t, int),
void (*rportfn)(lwkt_port_t, lwkt_msg_t),
int (*dmsgfn)(lwkt_port_t, lwkt_msg_t),
int (*pportfn_oncpu)(lwkt_port_t, lwkt_msg_t))
{
bzero(port, sizeof(*port));
port->mp_cpuid = -1;
TAILQ_INIT(&port->mp_msgq);
TAILQ_INIT(&port->mp_msgq_prio);
port->mp_getport = gportfn;
port->mp_putport = pportfn;
port->mp_waitmsg = wmsgfn;
port->mp_waitport = wportfn;
port->mp_replyport = rportfn;
port->mp_dropmsg = dmsgfn;
port->mp_putport_oncpu = pportfn_oncpu;
}
static __inline
void
_lwkt_schedule_msg(thread_t td, int flags)
{
lwkt_schedule(td);
}
void
lwkt_initport_thread(lwkt_port_t port, thread_t td)
{
_lwkt_initport(port,
lwkt_thread_getport,
lwkt_thread_putport,
lwkt_thread_waitmsg,
lwkt_thread_waitport,
lwkt_thread_replyport,
lwkt_thread_dropmsg,
lwkt_thread_putport);
port->mpu_td = td;
}
void
lwkt_initport_spin(lwkt_port_t port, thread_t td, boolean_t fixed_cpuid)
{
int (*dmsgfn)(lwkt_port_t, lwkt_msg_t);
int (*pportfn_oncpu)(lwkt_port_t, lwkt_msg_t);
if (td == NULL)
dmsgfn = lwkt_panic_dropmsg;
else
dmsgfn = lwkt_spin_dropmsg;
if (fixed_cpuid)
pportfn_oncpu = lwkt_spin_putport_oncpu;
else
pportfn_oncpu = lwkt_panic_putport_oncpu;
_lwkt_initport(port,
lwkt_spin_getport,
lwkt_spin_putport,
lwkt_spin_waitmsg,
lwkt_spin_waitport,
lwkt_spin_replyport,
dmsgfn,
pportfn_oncpu);
spin_init(&port->mpu_spin, "lwktinitport");
port->mpu_td = td;
if (fixed_cpuid)
port->mp_cpuid = td->td_gd->gd_cpuid;
}
void
lwkt_initport_serialize(lwkt_port_t port, struct lwkt_serialize *slz)
{
_lwkt_initport(port,
lwkt_serialize_getport,
lwkt_serialize_putport,
lwkt_serialize_waitmsg,
lwkt_serialize_waitport,
lwkt_serialize_replyport,
lwkt_panic_dropmsg,
lwkt_panic_putport_oncpu);
port->mpu_serialize = slz;
}
void
lwkt_initport_replyonly_null(lwkt_port_t port)
{
_lwkt_initport(port,
lwkt_panic_getport,
lwkt_panic_putport,
lwkt_panic_waitmsg,
lwkt_panic_waitport,
lwkt_null_replyport,
lwkt_panic_dropmsg,
lwkt_panic_putport_oncpu);
}
void
lwkt_initport_replyonly(lwkt_port_t port,
void (*rportfn)(lwkt_port_t, lwkt_msg_t))
{
_lwkt_initport(port, lwkt_panic_getport, lwkt_panic_putport,
lwkt_panic_waitmsg, lwkt_panic_waitport,
rportfn, lwkt_panic_dropmsg,
lwkt_panic_putport_oncpu);
}
void
lwkt_initport_putonly(lwkt_port_t port,
int (*pportfn)(lwkt_port_t, lwkt_msg_t))
{
_lwkt_initport(port, lwkt_panic_getport, pportfn,
lwkt_panic_waitmsg, lwkt_panic_waitport,
lwkt_panic_replyport, lwkt_panic_dropmsg,
lwkt_panic_putport_oncpu);
}
void
lwkt_initport_panic(lwkt_port_t port)
{
_lwkt_initport(port,
lwkt_panic_getport, lwkt_panic_putport,
lwkt_panic_waitmsg, lwkt_panic_waitport,
lwkt_panic_replyport, lwkt_panic_dropmsg,
lwkt_panic_putport_oncpu);
}
static __inline
void
_lwkt_pullmsg(lwkt_port_t port, lwkt_msg_t msg)
{
lwkt_msg_queue *queue;
if (__predict_false(msg->ms_flags & MSGF_PRIORITY))
queue = &port->mp_msgq_prio;
else
queue = &port->mp_msgq;
TAILQ_REMOVE(queue, msg, ms_node);
atomic_clear_int(&msg->ms_flags, MSGF_QUEUED);
}
static __inline
void
_lwkt_pushmsg(lwkt_port_t port, lwkt_msg_t msg)
{
lwkt_msg_queue *queue;
atomic_set_int(&msg->ms_flags, MSGF_QUEUED);
if (__predict_false(msg->ms_flags & MSGF_PRIORITY))
queue = &port->mp_msgq_prio;
else
queue = &port->mp_msgq;
TAILQ_INSERT_TAIL(queue, msg, ms_node);
if (msg->ms_flags & MSGF_RECEIPT) {
atomic_clear_int(&msg->ms_flags, MSGF_RECEIPT);
msg->ms_receiptfn(msg, port);
}
}
static __inline
lwkt_msg_t
_lwkt_pollmsg(lwkt_port_t port)
{
lwkt_msg_t msg;
msg = TAILQ_FIRST(&port->mp_msgq_prio);
if (__predict_false(msg != NULL))
return msg;
return TAILQ_FIRST(&port->mp_msgq);
}
static __inline
void
_lwkt_enqueue_reply(lwkt_port_t port, lwkt_msg_t msg)
{
_lwkt_pushmsg(port, msg);
atomic_set_int(&msg->ms_flags, MSGF_REPLY | MSGF_DONE);
}
static
void
lwkt_thread_replyport_remote(lwkt_msg_t msg)
{
lwkt_port_t port = msg->ms_reply_port;
int flags;
if (port->mpu_td->td_gd != mycpu) {
lwkt_send_ipiq(port->mpu_td->td_gd,
(ipifunc1_t)lwkt_thread_replyport_remote, msg);
return;
}
#ifdef INVARIANTS
KKASSERT(msg->ms_flags & MSGF_INTRANSIT);
msg->ms_flags &= ~MSGF_INTRANSIT;
#endif
flags = msg->ms_flags;
if (msg->ms_flags & MSGF_SYNC) {
cpu_sfence();
msg->ms_flags |= MSGF_REPLY | MSGF_DONE;
} else {
_lwkt_enqueue_reply(port, msg);
}
if (port->mp_flags & MSGPORTF_WAITING)
_lwkt_schedule_msg(port->mpu_td, flags);
}
static
void
lwkt_thread_replyport(lwkt_port_t port, lwkt_msg_t msg)
{
int flags;
KKASSERT((msg->ms_flags & (MSGF_DONE|MSGF_QUEUED|MSGF_INTRANSIT)) == 0);
if (msg->ms_flags & MSGF_SYNC) {
if (port->mpu_td->td_gd == mycpu) {
crit_enter();
flags = msg->ms_flags;
cpu_sfence();
msg->ms_flags |= MSGF_DONE | MSGF_REPLY;
if (port->mp_flags & MSGPORTF_WAITING)
_lwkt_schedule_msg(port->mpu_td, flags);
crit_exit();
} else {
#ifdef INVARIANTS
atomic_set_int(&msg->ms_flags, MSGF_INTRANSIT);
#endif
atomic_set_int(&msg->ms_flags, MSGF_REPLY);
lwkt_send_ipiq(port->mpu_td->td_gd,
(ipifunc1_t)lwkt_thread_replyport_remote, msg);
}
} else {
if (port->mpu_td->td_gd == mycpu) {
crit_enter();
_lwkt_enqueue_reply(port, msg);
if (port->mp_flags & MSGPORTF_WAITING)
_lwkt_schedule_msg(port->mpu_td, msg->ms_flags);
crit_exit();
} else {
#ifdef INVARIANTS
atomic_set_int(&msg->ms_flags, MSGF_INTRANSIT);
#endif
atomic_set_int(&msg->ms_flags, MSGF_REPLY);
lwkt_send_ipiq(port->mpu_td->td_gd,
(ipifunc1_t)lwkt_thread_replyport_remote, msg);
}
}
}
static int
lwkt_thread_dropmsg(lwkt_port_t port, lwkt_msg_t msg)
{
int error;
KASSERT(port->mpu_td == curthread,
("message could only be dropped in the same thread "
"as the message target port thread"));
crit_enter_quick(port->mpu_td);
if ((msg->ms_flags & (MSGF_REPLY|MSGF_QUEUED)) == MSGF_QUEUED) {
_lwkt_pullmsg(port, msg);
atomic_set_int(&msg->ms_flags, MSGF_DONE);
error = 0;
} else {
error = ENOENT;
}
crit_exit_quick(port->mpu_td);
return (error);
}
static
void
lwkt_thread_putport_remote(lwkt_msg_t msg)
{
lwkt_port_t port = msg->ms_target_port;
if (port->mpu_td->td_gd != mycpu) {
lwkt_send_ipiq(port->mpu_td->td_gd,
(ipifunc1_t)lwkt_thread_putport_remote, msg);
return;
}
#ifdef INVARIANTS
KKASSERT(msg->ms_flags & MSGF_INTRANSIT);
atomic_clear_int(&msg->ms_flags, MSGF_INTRANSIT);
#endif
_lwkt_pushmsg(port, msg);
if (port->mp_flags & MSGPORTF_WAITING)
_lwkt_schedule_msg(port->mpu_td, msg->ms_flags);
}
static
int
lwkt_thread_putport(lwkt_port_t port, lwkt_msg_t msg)
{
KKASSERT((msg->ms_flags & (MSGF_DONE | MSGF_REPLY)) == 0);
msg->ms_target_port = port;
if (port->mpu_td->td_gd == mycpu) {
crit_enter();
_lwkt_pushmsg(port, msg);
if (port->mp_flags & MSGPORTF_WAITING)
_lwkt_schedule_msg(port->mpu_td, msg->ms_flags);
crit_exit();
} else {
#ifdef INVARIANTS
atomic_set_int(&msg->ms_flags, MSGF_INTRANSIT);
#endif
lwkt_send_ipiq(port->mpu_td->td_gd,
(ipifunc1_t)lwkt_thread_putport_remote, msg);
}
return (EASYNC);
}
static
void *
lwkt_thread_getport(lwkt_port_t port)
{
lwkt_msg_t msg;
KKASSERT(port->mpu_td == curthread);
crit_enter_quick(port->mpu_td);
if ((msg = _lwkt_pollmsg(port)) != NULL)
_lwkt_pullmsg(port, msg);
crit_exit_quick(port->mpu_td);
return(msg);
}
static
int
lwkt_thread_waitmsg(lwkt_msg_t msg, int flags)
{
thread_t td = curthread;
KASSERT((msg->ms_flags & MSGF_DROPABLE) == 0,
("can't wait dropable message"));
if ((msg->ms_flags & MSGF_DONE) == 0) {
lwkt_port_t port = msg->ms_reply_port;
int sentabort;
KKASSERT(port->mpu_td == td);
crit_enter_quick(td);
sentabort = 0;
while ((msg->ms_flags & MSGF_DONE) == 0) {
port->mp_flags |= MSGPORTF_WAITING;
if (sentabort == 0) {
if ((sentabort = lwkt_sleep("waitmsg", flags)) != 0) {
lwkt_abortmsg(msg);
}
} else {
lwkt_sleep("waitabt", 0);
}
port->mp_flags &= ~MSGPORTF_WAITING;
}
if (msg->ms_flags & MSGF_QUEUED)
_lwkt_pullmsg(port, msg);
crit_exit_quick(td);
} else {
crit_enter_quick(td);
if (msg->ms_flags & MSGF_QUEUED) {
lwkt_port_t port = msg->ms_reply_port;
thread_t td __debugvar = curthread;
KKASSERT(port->mpu_td == td);
_lwkt_pullmsg(port, msg);
}
crit_exit_quick(td);
}
return(msg->ms_error);
}
static
void *
lwkt_thread_waitport(lwkt_port_t port, int flags)
{
thread_t td = curthread;
lwkt_msg_t msg;
int error;
KKASSERT(port->mpu_td == td);
crit_enter_quick(td);
while ((msg = _lwkt_pollmsg(port)) == NULL) {
port->mp_flags |= MSGPORTF_WAITING;
error = lwkt_sleep("waitport", flags);
port->mp_flags &= ~MSGPORTF_WAITING;
if (error)
goto done;
}
_lwkt_pullmsg(port, msg);
done:
crit_exit_quick(td);
return(msg);
}
static
void *
lwkt_spin_getport(lwkt_port_t port)
{
lwkt_msg_t msg;
spin_lock(&port->mpu_spin);
if ((msg = _lwkt_pollmsg(port)) != NULL)
_lwkt_pullmsg(port, msg);
spin_unlock(&port->mpu_spin);
return(msg);
}
static __inline int
lwkt_spin_putport_only(lwkt_port_t port, lwkt_msg_t msg)
{
int dowakeup;
KKASSERT((msg->ms_flags & (MSGF_DONE | MSGF_REPLY)) == 0);
msg->ms_target_port = port;
spin_lock(&port->mpu_spin);
_lwkt_pushmsg(port, msg);
dowakeup = 0;
if (port->mp_flags & MSGPORTF_WAITING) {
port->mp_flags &= ~MSGPORTF_WAITING;
dowakeup = 1;
}
spin_unlock(&port->mpu_spin);
return dowakeup;
}
static
int
lwkt_spin_putport(lwkt_port_t port, lwkt_msg_t msg)
{
if (lwkt_spin_putport_only(port, msg))
wakeup(port);
return (EASYNC);
}
static
int
lwkt_spin_putport_oncpu(lwkt_port_t port, lwkt_msg_t msg)
{
KASSERT(port->mp_cpuid == mycpuid,
("cpu mismatch, can't do oncpu putport; port cpu%d, curcpu cpu%d",
port->mp_cpuid, mycpuid));
if (lwkt_spin_putport_only(port, msg))
wakeup_mycpu(port);
return (EASYNC);
}
static
int
lwkt_spin_waitmsg(lwkt_msg_t msg, int flags)
{
lwkt_port_t port;
int sentabort;
int error;
KASSERT((msg->ms_flags & MSGF_DROPABLE) == 0,
("can't wait dropable message"));
port = msg->ms_reply_port;
if ((msg->ms_flags & MSGF_DONE) == 0) {
sentabort = 0;
spin_lock(&port->mpu_spin);
while ((msg->ms_flags & MSGF_DONE) == 0) {
void *won;
if (msg->ms_flags & MSGF_SYNC) {
won = msg;
atomic_set_int(&msg->ms_flags, MSGF_WAITING);
} else {
won = port;
port->mp_flags |= MSGPORTF_WAITING;
}
if ((flags & PCATCH) && sentabort == 0) {
error = ssleep(won, &port->mpu_spin, PCATCH, "waitmsg", 0);
if (error) {
sentabort = error;
spin_unlock(&port->mpu_spin);
lwkt_abortmsg(msg);
spin_lock(&port->mpu_spin);
}
} else {
error = ssleep(won, &port->mpu_spin, 0, "waitmsg", 0);
}
}
if (sentabort && msg->ms_error == EINTR)
msg->ms_error = sentabort;
if (msg->ms_flags & MSGF_QUEUED)
_lwkt_pullmsg(port, msg);
spin_unlock(&port->mpu_spin);
} else {
spin_lock(&port->mpu_spin);
if (msg->ms_flags & MSGF_QUEUED) {
_lwkt_pullmsg(port, msg);
}
spin_unlock(&port->mpu_spin);
}
return(msg->ms_error);
}
static
void *
lwkt_spin_waitport(lwkt_port_t port, int flags)
{
lwkt_msg_t msg;
int error;
spin_lock(&port->mpu_spin);
while ((msg = _lwkt_pollmsg(port)) == NULL) {
port->mp_flags |= MSGPORTF_WAITING;
error = ssleep(port, &port->mpu_spin, flags, "waitport", 0);
if (error) {
spin_unlock(&port->mpu_spin);
return(NULL);
}
}
_lwkt_pullmsg(port, msg);
spin_unlock(&port->mpu_spin);
return(msg);
}
static
void
lwkt_spin_replyport(lwkt_port_t port, lwkt_msg_t msg)
{
int dowakeup;
KKASSERT((msg->ms_flags & (MSGF_DONE|MSGF_QUEUED)) == 0);
if (msg->ms_flags & MSGF_SYNC) {
spin_lock(&port->mpu_spin);
msg->ms_flags |= MSGF_DONE | MSGF_REPLY;
dowakeup = 0;
if (msg->ms_flags & MSGF_WAITING) {
msg->ms_flags &= ~MSGF_WAITING;
dowakeup = 1;
}
spin_unlock(&port->mpu_spin);
if (dowakeup)
wakeup(msg);
} else {
spin_lock(&port->mpu_spin);
_lwkt_enqueue_reply(port, msg);
dowakeup = 0;
if (port->mp_flags & MSGPORTF_WAITING) {
port->mp_flags &= ~MSGPORTF_WAITING;
dowakeup = 1;
}
spin_unlock(&port->mpu_spin);
if (dowakeup)
wakeup(port);
}
}
static int
lwkt_spin_dropmsg(lwkt_port_t port, lwkt_msg_t msg)
{
int error;
KASSERT(port->mpu_td == curthread,
("message could only be dropped in the same thread "
"as the message target port thread\n"));
spin_lock(&port->mpu_spin);
if ((msg->ms_flags & (MSGF_REPLY|MSGF_QUEUED)) == MSGF_QUEUED) {
_lwkt_pullmsg(port, msg);
msg->ms_flags |= MSGF_DONE;
error = 0;
} else {
error = ENOENT;
}
spin_unlock(&port->mpu_spin);
return (error);
}
static
void *
lwkt_serialize_getport(lwkt_port_t port)
{
lwkt_msg_t msg;
ASSERT_SERIALIZED(port->mpu_serialize);
if ((msg = _lwkt_pollmsg(port)) != NULL)
_lwkt_pullmsg(port, msg);
return(msg);
}
static
int
lwkt_serialize_putport(lwkt_port_t port, lwkt_msg_t msg)
{
KKASSERT((msg->ms_flags & (MSGF_DONE | MSGF_REPLY)) == 0);
ASSERT_SERIALIZED(port->mpu_serialize);
msg->ms_target_port = port;
_lwkt_pushmsg(port, msg);
if (port->mp_flags & MSGPORTF_WAITING) {
port->mp_flags &= ~MSGPORTF_WAITING;
wakeup(port);
}
return (EASYNC);
}
static
int
lwkt_serialize_waitmsg(lwkt_msg_t msg, int flags)
{
lwkt_port_t port;
int sentabort;
int error;
KASSERT((msg->ms_flags & MSGF_DROPABLE) == 0,
("can't wait dropable message"));
if ((msg->ms_flags & MSGF_DONE) == 0) {
port = msg->ms_reply_port;
ASSERT_SERIALIZED(port->mpu_serialize);
sentabort = 0;
while ((msg->ms_flags & MSGF_DONE) == 0) {
void *won;
if (msg->ms_flags & MSGF_SYNC) {
won = msg;
} else {
won = port;
port->mp_flags |= MSGPORTF_WAITING;
}
if ((flags & PCATCH) && sentabort == 0) {
error = zsleep(won, port->mpu_serialize, PCATCH, "waitmsg", 0);
if (error) {
sentabort = error;
lwkt_serialize_exit(port->mpu_serialize);
lwkt_abortmsg(msg);
lwkt_serialize_enter(port->mpu_serialize);
}
} else {
error = zsleep(won, port->mpu_serialize, 0, "waitmsg", 0);
}
}
if (sentabort && msg->ms_error == EINTR)
msg->ms_error = sentabort;
if (msg->ms_flags & MSGF_QUEUED)
_lwkt_pullmsg(port, msg);
} else {
if (msg->ms_flags & MSGF_QUEUED) {
port = msg->ms_reply_port;
ASSERT_SERIALIZED(port->mpu_serialize);
_lwkt_pullmsg(port, msg);
}
}
return(msg->ms_error);
}
static
void *
lwkt_serialize_waitport(lwkt_port_t port, int flags)
{
lwkt_msg_t msg;
int error;
ASSERT_SERIALIZED(port->mpu_serialize);
while ((msg = _lwkt_pollmsg(port)) == NULL) {
port->mp_flags |= MSGPORTF_WAITING;
error = zsleep(port, port->mpu_serialize, flags, "waitport", 0);
if (error)
return(NULL);
}
_lwkt_pullmsg(port, msg);
return(msg);
}
static
void
lwkt_serialize_replyport(lwkt_port_t port, lwkt_msg_t msg)
{
KKASSERT((msg->ms_flags & (MSGF_DONE|MSGF_QUEUED)) == 0);
ASSERT_SERIALIZED(port->mpu_serialize);
if (msg->ms_flags & MSGF_SYNC) {
msg->ms_flags |= MSGF_DONE | MSGF_REPLY;
wakeup(msg);
} else {
_lwkt_enqueue_reply(port, msg);
if (port->mp_flags & MSGPORTF_WAITING) {
port->mp_flags &= ~MSGPORTF_WAITING;
wakeup(port);
}
}
}
static
void
lwkt_null_replyport(lwkt_port_t port, lwkt_msg_t msg)
{
msg->ms_flags |= MSGF_DONE | MSGF_REPLY;
}
static
void *
lwkt_panic_getport(lwkt_port_t port)
{
panic("lwkt_getport() illegal on port %p", port);
}
static
int
lwkt_panic_putport(lwkt_port_t port, lwkt_msg_t msg)
{
panic("lwkt_begin/do/sendmsg() illegal on port %p msg %p", port, msg);
}
static
int
lwkt_panic_waitmsg(lwkt_msg_t msg, int flags)
{
panic("port %p msg %p cannot be waited on", msg->ms_reply_port, msg);
}
static
void *
lwkt_panic_waitport(lwkt_port_t port, int flags)
{
panic("port %p cannot be waited on", port);
}
static
void
lwkt_panic_replyport(lwkt_port_t port, lwkt_msg_t msg)
{
panic("lwkt_replymsg() is illegal on port %p msg %p", port, msg);
}
static
int
lwkt_panic_dropmsg(lwkt_port_t port, lwkt_msg_t msg)
{
panic("lwkt_dropmsg() is illegal on port %p msg %p", port, msg);
return (ENOENT);
}
static
int
lwkt_panic_putport_oncpu(lwkt_port_t port, lwkt_msg_t msg)
{
panic("lwkt_begin_oncpu/sendmsg_oncpu() illegal on port %p msg %p",
port, msg);
return (ENOENT);
}