File:  [DragonFly] / src / sys / kern / lwkt_msgport.c
Revision 1.12: download - view: text, annotated - select for diffs
Thu Dec 4 20:09:33 2003 UTC (11 years ago) by dillon
Branches: MAIN
CVS tags: HEAD
General cleanups as part of the libcaps userland threading work.

    1: /*
    2:  * Copyright (c) 2003 Matthew Dillon <dillon@backplane.com>
    3:  * All rights reserved.
    4:  *
    5:  * Redistribution and use in source and binary forms, with or without
    6:  * modification, are permitted provided that the following conditions
    7:  * are met:
    8:  * 1. Redistributions of source code must retain the above copyright
    9:  *    notice, this list of conditions and the following disclaimer.
   10:  * 2. Redistributions in binary form must reproduce the above copyright
   11:  *    notice, this list of conditions and the following disclaimer in the
   12:  *    documentation and/or other materials provided with the distribution.
   13:  *
   14:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24:  * SUCH DAMAGE.
   25:  *
   26:  * NOTE! This file may be compiled for userland libraries as well as for
   27:  * the kernel.
   28:  *
   29:  * $DragonFly: src/sys/kern/lwkt_msgport.c,v 1.12 2003/12/04 20:09:33 dillon Exp $
   30:  */
   31: 
   32: #ifdef _KERNEL
   33: 
   34: #include <sys/param.h>
   35: #include <sys/systm.h>
   36: #include <sys/kernel.h>
   37: #include <sys/proc.h>
   38: #include <sys/rtprio.h>
   39: #include <sys/queue.h>
   40: #include <sys/sysctl.h>
   41: #include <sys/kthread.h>
   42: #include <machine/cpu.h>
   43: #include <sys/lock.h>
   44: 
   45: #include <vm/vm.h>
   46: #include <vm/vm_param.h>
   47: #include <vm/vm_kern.h>
   48: #include <vm/vm_object.h>
   49: #include <vm/vm_page.h>
   50: #include <vm/vm_map.h>
   51: #include <vm/vm_pager.h>
   52: #include <vm/vm_extern.h>
   53: #include <vm/vm_zone.h>
   54: 
   55: #include <sys/thread2.h>
   56: #include <sys/msgport2.h>
   57: 
   58: #include <machine/stdarg.h>
   59: #include <machine/ipl.h>
   60: #ifdef SMP
   61: #include <machine/smp.h>
   62: #endif
   63: 
   64: #else
   65: 
   66: #include <sys/stdint.h>
   67: #include <libcaps/thread.h>
   68: #include <sys/thread.h>
   69: #include <sys/msgport.h>
   70: #include <sys/errno.h>
   71: #include <libcaps/globaldata.h>
   72: #include <sys/thread2.h>
   73: #include <sys/msgport2.h>
   74: #include <string.h>
   75: 
   76: #endif /* _KERNEL */
   77: 
   78: 
   79: /************************************************************************
   80:  *				MESSAGE FUNCTIONS			*
   81:  ************************************************************************/
   82: 
   83: static int lwkt_default_putport(lwkt_port_t port, lwkt_msg_t msg);
   84: static void *lwkt_default_waitport(lwkt_port_t port, lwkt_msg_t msg);
   85: static void lwkt_default_replyport(lwkt_port_t port, lwkt_msg_t msg);
   86: static void lwkt_default_abortport(lwkt_port_t port, lwkt_msg_t msg);
   87: static void lwkt_replyport_remote(lwkt_msg_t msg);
   88: static void lwkt_putport_remote(lwkt_msg_t msg);
   89: 
   90: void
   91: lwkt_initmsg_td(lwkt_msg_t msg, thread_t td)
   92: {
   93:     lwkt_initmsg(msg, &td->td_msgport, 0);
   94: }
   95: 
   96: /*
   97:  * lwkt_sendmsg()
   98:  *
   99:  *	Send a message asynchronously.  This function requests asynchronous
  100:  *	completion and calls lwkt_beginmsg().  If the target port decides to
  101:  *	run the message synchronously this function will automatically queue
  102:  *	the message to the current thread's message queue to present a
  103:  *	consistent interface to the caller. 
  104:  *
  105:  *	The message's ms_cmd must be initialized and its ms_flags must be
  106:  *	at least zero'd out.  lwkt_sendmsg() will initialize the message's
  107:  *	reply port to the current thread's built-in reply port.
  108:  */
  109: void
  110: lwkt_sendmsg(lwkt_port_t port, lwkt_msg_t msg)
  111: {
  112:     int error;
  113: 
  114:     msg->ms_flags |= MSGF_ASYNC;
  115:     msg->ms_flags &= ~(MSGF_REPLY | MSGF_QUEUED);
  116:     msg->ms_reply_port = &curthread->td_msgport;
  117:     if ((error = lwkt_beginmsg(port, msg)) != EASYNC) {
  118: 	lwkt_replymsg(msg, error);
  119:     }
  120: }
  121: 
  122: /*
  123:  * lwkt_domsg()
  124:  *
  125:  *	Send a message synchronously.  This function requests synchronous
  126:  *	completion and calls lwkt_beginmsg().  If the target port decides to
  127:  *	run the message asynchronously this function will block waiting for
  128:  *	the message to complete.  Since MSGF_ASYNC is not set the target
  129:  *	will not attempt to queue the reply to a reply port but will simply
  130:  *	wake up anyone waiting on the message.
  131:  *
  132:  *	A synchronous error code is always returned.
  133:  *
  134:  *	The message's ms_cmd must be initialized and its ms_flags must be
  135:  *	at least zero'd out.  lwkt_domsg() will initialize the message's
  136:  *	reply port to the current thread's built-in reply port.
  137:  */
  138: int
  139: lwkt_domsg(lwkt_port_t port, lwkt_msg_t msg)
  140: {
  141:     int error;
  142: 
  143:     msg->ms_flags &= ~(MSGF_ASYNC | MSGF_REPLY | MSGF_QUEUED);
  144:     msg->ms_reply_port = &curthread->td_msgport;
  145:     if ((error = lwkt_beginmsg(port, msg)) == EASYNC) {
  146: 	error = lwkt_waitmsg(msg);
  147:     }
  148:     return(error);
  149: }
  150: 
  151: /************************************************************************
  152:  *				PORT FUNCTIONS				*
  153:  ************************************************************************/
  154: 
  155: /*
  156:  * lwkt_initport()
  157:  *
  158:  *	Initialize a port for use and assign it to the specified thread.
  159:  */
  160: void
  161: lwkt_initport(lwkt_port_t port, thread_t td)
  162: {
  163:     bzero(port, sizeof(*port));
  164:     TAILQ_INIT(&port->mp_msgq);
  165:     port->mp_td = td;
  166:     port->mp_putport = lwkt_default_putport;
  167:     port->mp_waitport =  lwkt_default_waitport;
  168:     port->mp_replyport = lwkt_default_replyport;
  169:     port->mp_abortport = lwkt_default_abortport;
  170: }
  171: 
  172: /*
  173:  * lwkt_getport()
  174:  *
  175:  *	Retrieve the next message from the port's message queue, return NULL
  176:  *	if no messages are pending.
  177:  *
  178:  *	The calling thread MUST own the port.
  179:  */
  180: void *
  181: lwkt_getport(lwkt_port_t port)
  182: {
  183:     lwkt_msg_t msg;
  184: 
  185:     KKASSERT(port->mp_td == curthread);
  186: 
  187:     crit_enter();
  188:     if ((msg = TAILQ_FIRST(&port->mp_msgq)) != NULL) {
  189: 	TAILQ_REMOVE(&port->mp_msgq, msg, ms_node);
  190: 	msg->ms_flags &= ~MSGF_QUEUED;
  191:     }
  192:     crit_exit();
  193:     return(msg);
  194: }
  195: 
  196: /*
  197:  * lwkt_default_replyport()
  198:  *
  199:  *	This function is typically assigned to the mp_replyport port vector.
  200:  *
  201:  *	The message is being returned to the specified port.  The port is
  202:  *	owned by the mp_td thread.  If we are on the same cpu as the mp_td
  203:  *	thread we can trivially queue the message to the messageq, otherwise
  204:  *	we have to send an ipi message to the correct cpu.   We then schedule
  205:  *	the target thread.
  206:  *
  207:  *	If MSGF_ASYNC is not set we do not bother queueing the message, we
  208:  *	just set the DONE bit.  
  209:  *
  210:  *	This inline must be entered with a critical section already held.
  211:  *	Note that the IPIQ callback function (*_remote) is entered with a
  212:  *	critical section already held, and we obtain one in lwkt_replyport().
  213:  */
  214: static __inline
  215: void
  216: _lwkt_replyport(lwkt_port_t port, lwkt_msg_t msg)
  217: {
  218:     thread_t td = port->mp_td;
  219: 
  220:     if (td->td_gd == mycpu) {
  221: 	TAILQ_INSERT_TAIL(&port->mp_msgq, msg, ms_node);
  222: 	msg->ms_flags |= MSGF_DONE | MSGF_REPLY | MSGF_QUEUED;
  223: 	if (port->mp_flags & MSGPORTF_WAITING)
  224: 	    lwkt_schedule(td);
  225:     } else {
  226: 	lwkt_send_ipiq(td->td_gd->gd_cpuid, (ipifunc_t)lwkt_replyport_remote, msg);
  227:     }
  228: }
  229: 
  230: static
  231: void
  232: lwkt_replyport_remote(lwkt_msg_t msg)
  233: {
  234:     _lwkt_replyport(msg->ms_reply_port, msg);
  235: }
  236: 
  237: static
  238: void
  239: lwkt_default_replyport(lwkt_port_t port, lwkt_msg_t msg)
  240: {
  241:     crit_enter();
  242:     if (msg->ms_flags & MSGF_ASYNC) {
  243: 	_lwkt_replyport(port, msg);
  244:     } else {
  245: 	msg->ms_flags |= MSGF_DONE;
  246: 	if (port->mp_flags & MSGPORTF_WAITING)
  247: 	    lwkt_schedule(port->mp_td);
  248:     }
  249:     crit_exit();
  250: }
  251: 
  252: /*
  253:  * lwkt_default_putport()
  254:  *
  255:  *	This function is typically assigned to the mp_putport port vector.
  256:  *
  257:  *	Queue a message to the target port and wakeup the thread owning it.
  258:  *	This function always returns EASYNC and may be assigned to a
  259:  *	message port's mp_putport function vector.
  260:  *
  261:  *	You must already be in a critical section when calling
  262:  *	the inline function.  The _remote function will be in a critical
  263:  *	section due to being called from the IPI, and lwkt_default_putport() 
  264:  *	enters a critical section.
  265:  */
  266: static
  267: __inline
  268: void
  269: _lwkt_putport(lwkt_port_t port, lwkt_msg_t msg)
  270: {
  271:     thread_t td = port->mp_td;
  272: 
  273:     if (td->td_gd == mycpu) {
  274: 	TAILQ_INSERT_TAIL(&port->mp_msgq, msg, ms_node);
  275: 	msg->ms_flags |= MSGF_QUEUED;
  276: 	if (port->mp_flags & MSGPORTF_WAITING)
  277: 	    lwkt_schedule(td);
  278:     } else {
  279: 	msg->ms_target_port = port;
  280: 	lwkt_send_ipiq(td->td_gd->gd_cpuid, (ipifunc_t)lwkt_putport_remote, msg);
  281:     }
  282: }
  283: 
  284: static
  285: void
  286: lwkt_putport_remote(lwkt_msg_t msg)
  287: {
  288:     _lwkt_putport(msg->ms_target_port, msg);
  289: }
  290: 
  291: static
  292: int
  293: lwkt_default_putport(lwkt_port_t port, lwkt_msg_t msg)
  294: {
  295:     crit_enter();
  296:     msg->ms_flags &= ~MSGF_DONE;
  297:     _lwkt_putport(port, msg);
  298:     crit_exit();
  299:     return(EASYNC);
  300: }
  301: 
  302: /*
  303:  * lwkt_default_abortport()
  304:  *
  305:  *	This function is typically assigned to the mp_abortport port vector.
  306:  *
  307:  *	This vector is typically called via the message's ms_target_port
  308:  *	pointer.  It should be noted that ms_target_port may race against
  309:  *	a forwarding operation run on a different cpu.  Any implementation
  310:  *	of lwkt_abortport() must deal with potential races by following
  311:  *	the message to the next appropriate port.
  312:  *
  313:  *	This function is a NOP.  by defaults message ports have no abort
  314:  *	capabilities.  Remember that aborts are always optional so doing 
  315:  *	nothing is perfectly reasonable.
  316:  */
  317: static
  318: void
  319: lwkt_default_abortport(lwkt_port_t port, lwkt_msg_t msg)
  320: {
  321:     /* NOP */
  322: }
  323: 
  324: /*
  325:  * lwkt_default_waitport()
  326:  *
  327:  *	If msg is NULL, dequeue the next message from the port's message
  328:  *	queue, block until a message is ready.  This function never
  329:  *	returns NULL.
  330:  *
  331:  *	If msg is non-NULL, block until the requested message has been returned
  332:  *	to the port then dequeue and return it.
  333:  *
  334:  *	Note that the API does not currently support multiple threads waiting
  335:  * 	on a port.  By virtue of owning the port it is controlled by our
  336:  *	cpu and we can safely manipulate it's contents.
  337:  */
  338: static
  339: void *
  340: lwkt_default_waitport(lwkt_port_t port, lwkt_msg_t msg)
  341: {
  342:     KKASSERT(port->mp_td == curthread);
  343: 
  344:     crit_enter();
  345:     if (msg == NULL) {
  346: 	if ((msg = TAILQ_FIRST(&port->mp_msgq)) == NULL) {
  347: 	    port->mp_flags |= MSGPORTF_WAITING;
  348: 	    do {
  349: 		lwkt_deschedule_self();
  350: 		lwkt_switch();
  351: 	    } while ((msg = TAILQ_FIRST(&port->mp_msgq)) == NULL);
  352: 	    port->mp_flags &= ~MSGPORTF_WAITING;
  353: 	}
  354: 	TAILQ_REMOVE(&port->mp_msgq, msg, ms_node);
  355: 	msg->ms_flags &= ~MSGF_QUEUED;
  356:     } else {
  357: 	/*
  358: 	 * If the message is marked done by not queued it has already been
  359: 	 * pulled off the port and returned and we do not have to do anything.
  360: 	 * Otherwise we do not own the message have to wait for message
  361: 	 * completion.  Beware of cpu races if MSGF_DONE is not foudn to be
  362: 	 * set!
  363: 	 */
  364: 	if ((msg->ms_flags & (MSGF_DONE|MSGF_REPLY)) != MSGF_DONE) {
  365: 	    /*
  366: 	     * We must own the reply port to safely mess with it's contents.
  367: 	     */
  368: 	    port = msg->ms_reply_port;
  369: 	    KKASSERT(port->mp_td == curthread);
  370: 
  371: 	    crit_enter();
  372: 	    if ((msg->ms_flags & MSGF_DONE) == 0) {
  373: 		port->mp_flags |= MSGPORTF_WAITING; /* saved by the BGL */
  374: 		do {
  375: 		    lwkt_deschedule_self();
  376: 		    lwkt_switch();
  377: 		} while ((msg->ms_flags & MSGF_DONE) == 0);
  378: 		port->mp_flags &= ~MSGPORTF_WAITING; /* saved by the BGL */
  379: 	    }
  380: 	    /*
  381: 	     * We own the message now.
  382: 	     */
  383: 	    if (msg->ms_flags & MSGF_QUEUED) {
  384: 		msg->ms_flags &= ~MSGF_QUEUED;
  385: 		TAILQ_REMOVE(&port->mp_msgq, msg, ms_node);
  386: 	    }
  387: 	}
  388:     }
  389:     crit_exit();
  390:     return(msg);
  391: }
  392: