DragonFly On-Line Manual Pages
MSGPORT(9) DragonFly Kernel Developer's Manual MSGPORT(9)
NAME
lwkt_initport_thread, lwkt_initport_spin, lwkt_initport_serialize,
lwkt_initport_panic, lwkt_initport_replyonly_null,
lwkt_initport_replyonly, lwkt_initport_putonly, lwkt_sendmsg, lwkt_domsg,
lwkt_forwardmsg, lwkt_abortmsg, lwkt_initmsg, lwkt_initmsg_abortable,
lwkt_beginmsg, lwkt_replymsg, lwkt_getport, lwkt_waitport, lwkt_waitmsg,
lwkt_checkmsg, lwkt_dropmsg -- LWKT message passing interface
SYNOPSIS
#include <sys/msgport.h>
void
lwkt_initport_thread(lwkt_port_t port, struct thread *td);
void
lwkt_initport_spin(lwkt_port_t port, struct thread *td,
boolean_t fixed_cpuid);
void
lwkt_initport_serialize(lwkt_port_t port, struct lwkt_serialize *slz);
void
lwkt_initport_panic(lwkt_port_t port);
void
lwkt_initport_replyonly_null(lwkt_port_t port);
void
lwkt_initport_replyonly(lwkt_port_t port,
void (*rportfn)(lwkt_port_t, lwkt_msg_t));
void
lwkt_initport_putonly(lwkt_port_t port,
int (*pportfn)(lwkt_port_t, lwkt_msg_t));
void
lwkt_sendmsg(lwkt_port_t port, lwkt_msg_t msg);
int
lwkt_domsg(lwkt_port_t port, lwkt_msg_t msg, int flags);
int
lwkt_forwardmsg(lwkt_port_t port, lwkt_msg_t msg);
void
lwkt_abortmsg(lwkt_msg_t msg);
#include <sys/msgport2.h>
void
lwkt_initmsg(lwkt_msg_t msg, lwkt_port_t rport, int flags);
void
lwkt_initmsg_abortable(lwkt_msg_t msg, lwkt_port_t rport, int flags,
void (*abortfn)(lwkt_msg_t));
int
lwkt_beginmsg(lwkt_port_t port, lwkt_msg_t msg);
void
lwkt_replymsg(lwkt_msg_t msg, int error);
void *
lwkt_getport(lwkt_port_t port);
void *
lwkt_waitport(lwkt_port_t port, int flags);
int
lwkt_waitmsg(lwkt_msg_t msg, int flags);
int
lwkt_checkmsg(lwkt_msg_t msg);
int
lwkt_dropmsg(lwkt_msg_t msg);
DESCRIPTION
Light weight kernel threads in DragonFly may use a message passing
interface to communicate with each other. Messages are sent to message
ports. All light weight kernel threads have a built-in message port, but
you may create additional ports if necessary. The following types of
message ports are available:
o thread ports
o spin ports
o serializer ports
Ports of type `thread' are owned by a single light weight kernel thread.
When a message is sent to a port of type `thread', only the owner of that
port is allowed to retrieve the message from it. When a message is sent
to a port of type `spin' or to a port of type `serializer', multiple
threads are allowed to check that port for new messages and compete to
retrieve them. You define the port type when you initialize the port.
By default, the built-in port of every light weight kernel thread is
automatically initialized to type `thread'.
When a message is sent, the receiver should normally send back a reply.
The reply is sent to the reply port that is registered on the original
message. Messages can be replied to synchronously or asynchronously.
The sender may request a synchronous or asynchronous reply to the
message, however the target port will ultimately decide how the message
will be treated.
MESSAGE FUNCTIONS
Messages must be initialized before being used. The lwkt_initmsg()
function initializes a message. The rport argument identifies the reply
port which will be used for asynchronous replies. The flags argument
sets any required flags for this message. Flags passed this way will
simply be or'ed to any already existing flags on the message.
The lwkt_initmsg_abortable() function is similar to lwkt_initmsg() but it
takes an additional parameter abortfn which defines the abort function
for this message.
The lwkt_sendmsg() function requests an asynchronous reply, sends the
message and returns immediately. Under normal circumstances, users of
this function may always expect the reply to be queued to the reply port
registered on the message. The port argument defines the target port to
which the msg message will be sent.
The lwkt_domsg() function requests a synchronous reply, sends the message
and does not return until the message has been replied to. If the target
port supports synchronous reply, this function will return that reply
immediately. If not, and this is the most common case, this function
will block and wait for the reply to arrive and then return it. The port
argument defines the target port to which the msg message will be sent.
The lwkt_replymsg() function replies to a message that was processed
asynchronously by the target port. This function is used by the thread
on the receiving side. The msg argument is the message being replied to
and the error argument is the actual response to send back.
The lwkt_forwardmsg() simply forwards a message to another port. The
port argument defines the target port to which the msg message will be
sent.
If a message has been initialized as abortable, you can use the
lwkt_abortmsg() function to try to abort it. The abortfn passed upon the
initialisation with lwkt_initmsg_abortable() will be called by this
function.
The lwkt_dropmsg() will dequeue the specified message from the target
port it was sent to and makes it look like it was never sent. This
function can only be used by the thread that owns the target port.
PORT FUNCTIONS
The lwkt_initport_thread() initializes the specified port with the
default `thread' port type handlers. The td argument defines the owner
thread of the port and only that thread is allowed to receive messages on
it.
The lwkt_initport_spin() initializes the specified port with the default
`spin' port type handlers. The td argument defines the owner thread of
the port, for cases where thread built-in ports are initialized as `spin'
ports. If NULL is passed, then the port will not have a defined owner,
so functions like lwkt_dropmsg() will not be available for this port. If
we know that this `spin' port is accessed exclusively by threads on a
single CPU, we can set the fixed_cpuid argument to true, which will
prevent the occurrence of unnecessary IPIs trying to wake up threads on
other CPUs. This function will also initialize the embedded spinlock
within the lwkt_port structure which will protect subsequent port access.
The lwkt_initport_serialize() function initializes the specified port
with the default `serializer' port type handlers. The subsequent port
access will be protected by the passed slz serializer lock.
The lwkt_getport() function checks the specified port for available
messages, dequeues the first one and returns it. If no messages are
available then NULL is returned instead. This function is used by
threads on the receiving side.
The lwkt_waitport() function checks the specified port for available
messages, dequeues the first one and returns it. If no messages are
available then the caller thread will sleep until a message arrives on
the specified port. The flags argument defines the flags used for the
sleep. This function is used by threads on the receiving side.
SPECIAL PORT INITIALIZERS
The lwkt_initport_replyonly() function initializes a port which is used
only as reply port and may have a custom reply port handler. The reply
port handler is specified with the rportfn argument. All the other
handlers will panic the system if they are called. This initializer is
normally used on ports for freeing resources after the messages have
fulfilled their purpose.
The lwkt_initport_replyonly_null() function initializes a port which is
used only as reply port. The reply port handler will simply mark the
message as being done and will not attempt to queue it. All the other
handlers will panic the system if they are called.
The lwkt_initport_putonly() function initializes a port which is used
only as target port. The putport handler is specified with the pportfn
argument. All the other handlers will panic the system if they are
called.
The lwkt_initport_panic() function initializes a port which will panic
the system if any of its handlers are called. This function is sometimes
used to initialize a reply-only port which does not expect the messages
to be replied to, e.g. when the messages should be consumed by the
receiving thread and never replied back.
INTERNAL MESSAGE FUNCTIONS
The following functions are used only by the infrastructure, you should
not need to use them directly unless in very rare cases.
The lwkt_beginmsg() function simply calls the target port's putport
handler. This function is only called by the lwkt_sendmsg() and
lwkt_replymsg() functions. The putport handler returns EASYNC for
messages processed asynchronously or any other value for messages
processed synchronously. That return value of the putport handler is
propagated by this function. The port argument defines the target port
to which the msg message will be sent.
The lwkt_waitmsg() function puts the caller to sleep until the specified
msg message has been replied to. The flags argument defines the flags
used for the sleep.
IMPLEMENTATION NOTES
All the default putport handlers (used when a message is sent) currently
implement asynchronous putports only, i.e. all *_putport() handlers
return EASYNC. You can still have synchronous putport handlers (which
are run in the sender's context) but you have to implement the function
yourself and then override the default.
Port handler functions can be overridden with custom functions if
required. You can override the default putport handler by either using
the lwkt_initport_putonly() initializer, or by manipulating the
mp_putport handler pointer directly on the lwkt_port structure.
There is one such case where the putport handler is overridden in
sys/net/netisr.c. In that case, the putport handler is overridden to
detect a loopback message (when the target port belongs to the sending
thread). This special putport handler turns the sent message into a
direct function call instead of queueing it to the port.
The lwkt_replymsg() function works differently depending on the original
message request. If the message was originally an asynchronous request,
the reply will be queued to the sender's reply port. If the message was
originally a synchronous request, then this function will just write the
error response on the message and wake up the waiter without queueing the
message to the reply port. There is no need to queue in the synchronous
request case because the original sender had blocked waiting on this
specific message with lwkt_domsg().
As is the case with putport handler, the replyport handler can also be
overridden. You override the default replyport handler by using the
lwkt_initport_replyonly() or the lwkt_initport_replyonly_null() port
initializers, or by manipulating the mp_replyport handler pointer
directly on the lwkt_port structure.
The sent message structure is reused for replies. When a message is
replied to, the error response is written on the message which is
subsequently sent to the reply port.
FILES
The LWKT msgport implementation resides in sys/kern/lwkt_msgport.c.
EXAMPLES
/*
* Example 1: per CPU threads.
*
*/
#include <sys/thread.h>
#include <sys/msgport.h>
#include <sys/msgport2.h>
static void my_service_loop(void *dummy);
lwkt_port_t my_service_portfn(int cpu);
void my_service_sendmsg(lwkt_msg_t lmsg, int cpu);
int my_service_domsg(lwkt_msg_t lmsg, int cpu);
/* Array of per-CPU target ports */
struct lwkt_port *my_service_ports[MAXCPU];
/*
* Create per-cpu threads for handling msg processing. Remember that
* built-in lwkt ports are automatically initialized to type 'thread'
* so we don't need to initialize them explicitly.
*/
static void
my_per_cpu_service_init(void)
{
int i;
thread_t td;
for (i = 0; i < ncpus; ++i) {
lwkt_create(my_service_loop, NULL, &td,
NULL, 0, i, "myservice_cpu %d", i);
my_service_ports[i] = &td->td_msgport;
}
}
/*
* This is the routine executed by the service threads on each CPU.
*/
static void
my_service_loop(void *dummy __unused)
{
lwkt_msg_t msg;
thread_t td = curthread;
int cpu = curthread->td_gd->gd_cpuid;
while ((msg = lwkt_waitport(&td->td_msgport, 0)) != NULL) {
/* Do some work in the receiver thread context. */
kprintf("Received message on CPU %d.\n", cpu);
/* And finally reply to the message. */
lwkt_replymsg(msg, 0);
}
}
/*
* Given a CPU id, return our respective service port.
*/
__inline lwkt_port_t
my_service_portfn(int cpu)
{
return my_service_ports[cpu];
}
/*
* Send an asynchronous message to the service thread on a specific CPU.
*/
void
my_service_sendmsg(lwkt_msg_t lmsg, int cpu)
{
KKASSERT(cpu < ncpus);
lwkt_sendmsg(my_service_portfn(cpu), lmsg);
}
/*
* Send a synchronous message to the service thread on a specific CPU.
*/
int
my_service_domsg(lwkt_msg_t lmsg, int cpu)
{
KKASSERT(cpu < ncpus);
return lwkt_domsg(my_service_portfn(cpu), lmsg, 0);
}
/*
* Example use case. Initialize the service threads and send each one a
* message.
*/
static void
mod_load(void)
{
lwkt_msg lmsg;
lwkt_port_t builtin_port = &curthread->td_msgport;
int i;
my_per_cpu_service_init();
for (i=0; i<ncpus; ++i) {
kprintf("Sending msg to CPU %d.\n", i);
lwkt_initmsg(&lmsg, builtin_port, 0);
my_service_domsg(&lmsg, i);
}
}
/*
* Example 2: Dynamic allocated message passing with automatic free.
*
* This scenario is used when resources need to be freed after the
* message has been replied to. Features:
* - An argument is passed within the message.
* - Messages are allocated with kmalloc(). Replying to the message
* kfree()s it.
*/
#include <sys/thread.h>
#include <sys/msgport.h>
#include <sys/msgport2.h>
void my_service_queue(void *arg);
lwkt_port my_autofree_rport;
lwkt_port_t my_service_port;
/*
* Use this function to send messages with a void * argument to our
* service thread.
*/
void
my_service_queue(void *arg)
{
lwkt_msg_t msg;
msg = kmalloc(sizeof(*msg), M_TEMP, M_WAITOK);
/* Set reply port to autofree. */
lwkt_initmsg(msg, &my_autofree_rport, 0);
/* Attach the argument to the message. */
msg->u.ms_resultp = arg;
/* Send it. */
lwkt_sendmsg(my_service_port, msg);
}
/*
* This is the routine executed by our service thread.
*/
static void
my_service_loop(void *dummy __unused)
{
lwkt_msg_t msg;
thread_t td = curthread;
while ((msg = lwkt_waitport(&td->td_msgport, 0)) != NULL) {
/*
* Do some work in the receiver thread context. In this
* example, the sender wrote his name in the argument he
* sent us. We print it here.
*/
char *arg = msg->u.ms_resultp;
kprintf("%s: Hi %s! Got your msg.\n", curthread->td_comm,
arg);
/* And finally reply to the message. */
lwkt_replymsg(msg, 0);
}
}
static void
my_autofree_reply(lwkt_port_t port, lwkt_msg_t msg)
{
kfree(msg->u.ms_resultp, M_TEMP);
kfree(msg, M_TEMP);
}
static void
my_service_init(void)
{
thread_t tdp;
/* Initialize our auto free reply port. */
lwkt_initport_replyonly(&my_autofree_rport, my_autofree_reply);
/* Create our service thread on CPU 0. */
lwkt_create(my_service_loop, NULL, &tdp, NULL, 0, 0, "myservice");
my_service_port = &tdp->td_msgport;
}
/*
* Example use case. Initialize the service and send the current thread
* name to the service thread.
*/
static void
mod_load(void)
{
void *arg;
int len;
my_service_init();
len = strlen(curthread->td_comm);
arg = kmalloc(len + 1, M_TEMP, M_WAITOK);
bcopy(curthread->td_comm, arg, len + 1);
kprintf("%s: Sending message.\n", curthread->td_comm);
my_service_queue(arg);
}
SEE ALSO
serializer(9), sleep(9), spinlock(9)
HISTORY
The LWKT msgport interface first appeared in DragonFly 1.0.
AUTHORS
The msgport message passing interface implementation was written by
Matthew Dillon. This manual page was written by Nuno Antunes.
DragonFly 3.9 July 16, 2014 DragonFly 3.9