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