File:  [DragonFly] / src / sys / kern / lwkt_msgport.c
Revision 1.11: download - view: text, annotated - select for diffs
Mon Nov 24 23:56:07 2003 UTC (10 years, 9 months ago) by dillon
Branches: MAIN
CVS tags: HEAD
#include cleanups for lwkt_msgport.c and lwkt_thread.c... the committed
library name is libcaps, not liblwkt.

    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.11 2003/11/24 23:56:07 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: 
   75: #endif /* _KERNEL */
   76: 
   77: 
   78: /************************************************************************
   79:  *				MESSAGE FUNCTIONS			*
   80:  ************************************************************************/
   81: 
   82: static int lwkt_default_putport(lwkt_port_t port, lwkt_msg_t msg);
   83: static void *lwkt_default_waitport(lwkt_port_t port, lwkt_msg_t msg);
   84: static void lwkt_default_replyport(lwkt_port_t port, lwkt_msg_t msg);
   85: static void lwkt_default_abortport(lwkt_port_t port, lwkt_msg_t msg);
   86: static void lwkt_replyport_remote(lwkt_msg_t msg);
   87: static void lwkt_putport_remote(lwkt_msg_t msg);
   88: 
   89: void
   90: lwkt_initmsg_td(lwkt_msg_t msg, thread_t td)
   91: {
   92:     lwkt_initmsg(msg, &td->td_msgport, 0);
   93: }
   94: 
   95: /*
   96:  * lwkt_sendmsg()
   97:  *
   98:  *	Send a message asynchronously.  This function requests asynchronous
   99:  *	completion and calls lwkt_beginmsg().  If the target port decides to
  100:  *	run the message synchronously this function will automatically queue
  101:  *	the message to the current thread's message queue to present a
  102:  *	consistent interface to the caller. 
  103:  *
  104:  *	The message's ms_cmd must be initialized and its ms_flags must be
  105:  *	at least zero'd out.  lwkt_sendmsg() will initialize the message's
  106:  *	reply port to the current thread's built-in reply port.
  107:  */
  108: void
  109: lwkt_sendmsg(lwkt_port_t port, lwkt_msg_t msg)
  110: {
  111:     int error;
  112: 
  113:     msg->ms_flags |= MSGF_ASYNC;
  114:     msg->ms_flags &= ~(MSGF_REPLY | MSGF_QUEUED);
  115:     msg->ms_reply_port = &curthread->td_msgport;
  116:     if ((error = lwkt_beginmsg(port, msg)) != EASYNC) {
  117: 	lwkt_replymsg(msg, error);
  118:     }
  119: }
  120: 
  121: /*
  122:  * lwkt_domsg()
  123:  *
  124:  *	Send a message synchronously.  This function requests synchronous
  125:  *	completion and calls lwkt_beginmsg().  If the target port decides to
  126:  *	run the message asynchronously this function will block waiting for
  127:  *	the message to complete.  Since MSGF_ASYNC is not set the target
  128:  *	will not attempt to queue the reply to a reply port but will simply
  129:  *	wake up anyone waiting on the message.
  130:  *
  131:  *	A synchronous error code is always returned.
  132:  *
  133:  *	The message's ms_cmd must be initialized and its ms_flags must be
  134:  *	at least zero'd out.  lwkt_domsg() will initialize the message's
  135:  *	reply port to the current thread's built-in reply port.
  136:  */
  137: int
  138: lwkt_domsg(lwkt_port_t port, lwkt_msg_t msg)
  139: {
  140:     int error;
  141: 
  142:     msg->ms_flags &= ~(MSGF_ASYNC | MSGF_REPLY | MSGF_QUEUED);
  143:     msg->ms_reply_port = &curthread->td_msgport;
  144:     if ((error = lwkt_beginmsg(port, msg)) == EASYNC) {
  145: 	error = lwkt_waitmsg(msg);
  146:     }
  147:     return(error);
  148: }
  149: 
  150: /************************************************************************
  151:  *				PORT FUNCTIONS				*
  152:  ************************************************************************/
  153: 
  154: /*
  155:  * lwkt_initport()
  156:  *
  157:  *	Initialize a port for use and assign it to the specified thread.
  158:  */
  159: void
  160: lwkt_initport(lwkt_port_t port, thread_t td)
  161: {
  162:     bzero(port, sizeof(*port));
  163:     TAILQ_INIT(&port->mp_msgq);
  164:     port->mp_td = td;
  165:     port->mp_putport = lwkt_default_putport;
  166:     port->mp_waitport =  lwkt_default_waitport;
  167:     port->mp_replyport = lwkt_default_replyport;
  168:     port->mp_abortport = lwkt_default_abortport;
  169: }
  170: 
  171: /*
  172:  * lwkt_getport()
  173:  *
  174:  *	Retrieve the next message from the port's message queue, return NULL
  175:  *	if no messages are pending.
  176:  *
  177:  *	The calling thread MUST own the port.
  178:  */
  179: void *
  180: lwkt_getport(lwkt_port_t port)
  181: {
  182:     lwkt_msg_t msg;
  183: 
  184:     KKASSERT(port->mp_td == curthread);
  185: 
  186:     crit_enter();
  187:     if ((msg = TAILQ_FIRST(&port->mp_msgq)) != NULL) {
  188: 	TAILQ_REMOVE(&port->mp_msgq, msg, ms_node);
  189: 	msg->ms_flags &= ~MSGF_QUEUED;
  190:     }
  191:     crit_exit();
  192:     return(msg);
  193: }
  194: 
  195: /*
  196:  * lwkt_default_replyport()
  197:  *
  198:  *	This function is typically assigned to the mp_replyport port vector.
  199:  *
  200:  *	The message is being returned to the specified port.  The port is
  201:  *	owned by the mp_td thread.  If we are on the same cpu as the mp_td
  202:  *	thread we can trivially queue the message to the messageq, otherwise
  203:  *	we have to send an ipi message to the correct cpu.   We then schedule
  204:  *	the target thread.
  205:  *
  206:  *	If MSGF_ASYNC is not set we do not bother queueing the message, we
  207:  *	just set the DONE bit.  
  208:  *
  209:  *	This inline must be entered with a critical section already held.
  210:  *	Note that the IPIQ callback function (*_remote) is entered with a
  211:  *	critical section already held, and we obtain one in lwkt_replyport().
  212:  */
  213: static __inline
  214: void
  215: _lwkt_replyport(lwkt_port_t port, lwkt_msg_t msg)
  216: {
  217:     thread_t td = port->mp_td;
  218: 
  219:     if (td->td_gd == mycpu) {
  220: 	TAILQ_INSERT_TAIL(&port->mp_msgq, msg, ms_node);
  221: 	msg->ms_flags |= MSGF_DONE | MSGF_REPLY | MSGF_QUEUED;
  222: 	if (port->mp_flags & MSGPORTF_WAITING)
  223: 	    lwkt_schedule(td);
  224:     } else {
  225: 	lwkt_send_ipiq(td->td_gd->gd_cpuid, (ipifunc_t)lwkt_replyport_remote, msg);
  226:     }
  227: }
  228: 
  229: static
  230: void
  231: lwkt_replyport_remote(lwkt_msg_t msg)
  232: {
  233:     _lwkt_replyport(msg->ms_reply_port, msg);
  234: }
  235: 
  236: static
  237: void
  238: lwkt_default_replyport(lwkt_port_t port, lwkt_msg_t msg)
  239: {
  240:     crit_enter();
  241:     if (msg->ms_flags & MSGF_ASYNC) {
  242: 	_lwkt_replyport(port, msg);
  243:     } else {
  244: 	msg->ms_flags |= MSGF_DONE;
  245: 	if (port->mp_flags & MSGPORTF_WAITING)
  246: 	    lwkt_schedule(port->mp_td);
  247:     }
  248:     crit_exit();
  249: }
  250: 
  251: /*
  252:  * lwkt_default_putport()
  253:  *
  254:  *	This function is typically assigned to the mp_putport port vector.
  255:  *
  256:  *	Queue a message to the target port and wakeup the thread owning it.
  257:  *	This function always returns EASYNC and may be assigned to a
  258:  *	message port's mp_putport function vector.
  259:  *
  260:  *	You must already be in a critical section when calling
  261:  *	the inline function.  The _remote function will be in a critical
  262:  *	section due to being called from the IPI, and lwkt_default_putport() 
  263:  *	enters a critical section.
  264:  */
  265: static
  266: __inline
  267: void
  268: _lwkt_putport(lwkt_port_t port, lwkt_msg_t msg)
  269: {
  270:     thread_t td = port->mp_td;
  271: 
  272:     if (td->td_gd == mycpu) {
  273: 	TAILQ_INSERT_TAIL(&port->mp_msgq, msg, ms_node);
  274: 	msg->ms_flags |= MSGF_QUEUED;
  275: 	if (port->mp_flags & MSGPORTF_WAITING)
  276: 	    lwkt_schedule(td);
  277:     } else {
  278: 	msg->ms_target_port = port;
  279: 	lwkt_send_ipiq(td->td_gd->gd_cpuid, (ipifunc_t)lwkt_putport_remote, msg);
  280:     }
  281: }
  282: 
  283: static
  284: void
  285: lwkt_putport_remote(lwkt_msg_t msg)
  286: {
  287:     _lwkt_putport(msg->ms_target_port, msg);
  288: }
  289: 
  290: static
  291: int
  292: lwkt_default_putport(lwkt_port_t port, lwkt_msg_t msg)
  293: {
  294:     crit_enter();
  295:     msg->ms_flags &= ~MSGF_DONE;
  296:     _lwkt_putport(port, msg);
  297:     crit_exit();
  298:     return(EASYNC);
  299: }
  300: 
  301: /*
  302:  * lwkt_default_abortport()
  303:  *
  304:  *	This function is typically assigned to the mp_abortport port vector.
  305:  *
  306:  *	This vector is typically called via the message's ms_target_port
  307:  *	pointer.  It should be noted that ms_target_port may race against
  308:  *	a forwarding operation run on a different cpu.  Any implementation
  309:  *	of lwkt_abortport() must deal with potential races by following
  310:  *	the message to the next appropriate port.
  311:  *
  312:  *	This function is a NOP.  by defaults message ports have no abort
  313:  *	capabilities.  Remember that aborts are always optional so doing 
  314:  *	nothing is perfectly reasonable.
  315:  */
  316: static
  317: void
  318: lwkt_default_abortport(lwkt_port_t port, lwkt_msg_t msg)
  319: {
  320:     /* NOP */
  321: }
  322: 
  323: /*
  324:  * lwkt_default_waitport()
  325:  *
  326:  *	If msg is NULL, dequeue the next message from the port's message
  327:  *	queue, block until a message is ready.  This function never
  328:  *	returns NULL.
  329:  *
  330:  *	If msg is non-NULL, block until the requested message has been returned
  331:  *	to the port then dequeue and return it.
  332:  *
  333:  *	Note that the API does not currently support multiple threads waiting
  334:  * 	on a port.  By virtue of owning the port it is controlled by our
  335:  *	cpu and we can safely manipulate it's contents.
  336:  */
  337: static
  338: void *
  339: lwkt_default_waitport(lwkt_port_t port, lwkt_msg_t msg)
  340: {
  341:     KKASSERT(port->mp_td == curthread);
  342: 
  343:     crit_enter();
  344:     if (msg == NULL) {
  345: 	if ((msg = TAILQ_FIRST(&port->mp_msgq)) == NULL) {
  346: 	    port->mp_flags |= MSGPORTF_WAITING;
  347: 	    do {
  348: 		lwkt_deschedule_self();
  349: 		lwkt_switch();
  350: 	    } while ((msg = TAILQ_FIRST(&port->mp_msgq)) == NULL);
  351: 	    port->mp_flags &= ~MSGPORTF_WAITING;
  352: 	}
  353: 	TAILQ_REMOVE(&port->mp_msgq, msg, ms_node);
  354: 	msg->ms_flags &= ~MSGF_QUEUED;
  355:     } else {
  356: 	/*
  357: 	 * If the message is marked done by not queued it has already been
  358: 	 * pulled off the port and returned and we do not have to do anything.
  359: 	 * Otherwise we do not own the message have to wait for message
  360: 	 * completion.  Beware of cpu races if MSGF_DONE is not foudn to be
  361: 	 * set!
  362: 	 */
  363: 	if ((msg->ms_flags & (MSGF_DONE|MSGF_REPLY)) != MSGF_DONE) {
  364: 	    /*
  365: 	     * We must own the reply port to safely mess with it's contents.
  366: 	     */
  367: 	    port = msg->ms_reply_port;
  368: 	    KKASSERT(port->mp_td == curthread);
  369: 
  370: 	    crit_enter();
  371: 	    if ((msg->ms_flags & MSGF_DONE) == 0) {
  372: 		port->mp_flags |= MSGPORTF_WAITING; /* saved by the BGL */
  373: 		do {
  374: 		    lwkt_deschedule_self();
  375: 		    lwkt_switch();
  376: 		} while ((msg->ms_flags & MSGF_DONE) == 0);
  377: 		port->mp_flags &= ~MSGPORTF_WAITING; /* saved by the BGL */
  378: 	    }
  379: 	    /*
  380: 	     * We own the message now.
  381: 	     */
  382: 	    if (msg->ms_flags & MSGF_QUEUED) {
  383: 		msg->ms_flags &= ~MSGF_QUEUED;
  384: 		TAILQ_REMOVE(&port->mp_msgq, msg, ms_node);
  385: 	    }
  386: 	}
  387:     }
  388:     crit_exit();
  389:     return(msg);
  390: }
  391: