* Greatly reduce the complexity of the LWKT messaging and port abstraction.
[dragonfly/vkernel-mp.git] / sys / kern / lwkt_msgport.c
blob21633656cb098c7c4d330ba42c8a94e42d2be30a
1 /*
2 * Copyright (c) 2003,2004 The DragonFly Project. All rights reserved.
3 *
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
34 * NOTE! This file may be compiled for userland libraries as well as for
35 * the kernel.
37 * $DragonFly: src/sys/kern/lwkt_msgport.c,v 1.40 2007/05/23 08:57:04 dillon Exp $
40 #ifdef _KERNEL
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/kernel.h>
45 #include <sys/proc.h>
46 #include <sys/rtprio.h>
47 #include <sys/queue.h>
48 #include <sys/sysctl.h>
49 #include <sys/kthread.h>
50 #include <sys/signalvar.h>
51 #include <sys/signal2.h>
52 #include <machine/cpu.h>
53 #include <sys/lock.h>
55 #include <vm/vm.h>
56 #include <vm/vm_param.h>
57 #include <vm/vm_kern.h>
58 #include <vm/vm_object.h>
59 #include <vm/vm_page.h>
60 #include <vm/vm_map.h>
61 #include <vm/vm_pager.h>
62 #include <vm/vm_extern.h>
63 #include <vm/vm_zone.h>
65 #include <sys/thread2.h>
66 #include <sys/msgport2.h>
68 #include <machine/stdarg.h>
69 #include <machine/cpufunc.h>
70 #ifdef SMP
71 #include <machine/smp.h>
72 #endif
74 #include <sys/malloc.h>
75 MALLOC_DEFINE(M_LWKTMSG, "lwkt message", "lwkt message");
77 #else
79 #include <sys/stdint.h>
80 #include <libcaps/thread.h>
81 #include <sys/thread.h>
82 #include <sys/msgport.h>
83 #include <sys/errno.h>
84 #include <libcaps/globaldata.h>
85 #include <machine/cpufunc.h>
86 #include <sys/thread2.h>
87 #include <sys/msgport2.h>
88 #include <string.h>
90 #endif /* _KERNEL */
93 /************************************************************************
94 * MESSAGE FUNCTIONS *
95 ************************************************************************/
97 #ifdef SMP
98 static void lwkt_replyport_remote(lwkt_msg_t msg);
99 static void lwkt_putport_remote(lwkt_msg_t msg);
100 #endif
103 * lwkt_sendmsg()
105 * Request asynchronous completion and call lwkt_beginmsg(). The
106 * target port can opt to execute the message synchronously or
107 * asynchronously and this function will automatically queue the
108 * response if the target executes the message synchronously.
110 * NOTE: The message is in an indeterminant state until this call
111 * returns. The caller should not mess with it (e.g. try to abort it)
112 * until then.
114 void
115 lwkt_sendmsg(lwkt_port_t port, lwkt_msg_t msg)
117 int error;
119 KKASSERT(msg->ms_reply_port != NULL &&
120 (msg->ms_flags & (MSGF_DONE|MSGF_QUEUED)) == MSGF_DONE);
121 msg->ms_flags &= ~(MSGF_REPLY | MSGF_SYNC | MSGF_DONE);
122 if ((error = lwkt_beginmsg(port, msg)) != EASYNC) {
123 lwkt_replymsg(msg, error);
128 * lwkt_domsg()
130 * Request asynchronous completion and call lwkt_beginmsg(). The
131 * target port can opt to execute the message synchronously or
132 * asynchronously and this function will automatically queue the
133 * response if the target executes the message synchronously.
136 lwkt_domsg(lwkt_port_t port, lwkt_msg_t msg)
138 int error;
140 KKASSERT(msg->ms_reply_port != NULL &&
141 (msg->ms_flags & (MSGF_DONE|MSGF_QUEUED)) == MSGF_DONE);
142 msg->ms_flags &= ~(MSGF_REPLY | MSGF_DONE);
143 msg->ms_flags |= MSGF_SYNC;
144 if ((error = lwkt_beginmsg(port, msg)) == EASYNC) {
145 error = lwkt_waitmsg(msg);
146 } else {
147 msg->ms_flags |= MSGF_DONE | MSGF_REPLY;
149 return(error);
152 /************************************************************************
153 * PORT FUNCTIONS *
154 ************************************************************************/
157 * lwkt_initport()
159 * Initialize a port for use and assign it to the specified thread.
160 * The default reply function is to return the message to the originator.
162 void
163 lwkt_initport(lwkt_port_t port, thread_t td)
165 bzero(port, sizeof(*port));
166 TAILQ_INIT(&port->mp_msgq);
167 port->mp_td = td;
168 port->mp_putport = lwkt_default_putport;
169 port->mp_waitport = lwkt_default_waitport;
170 port->mp_replyport = lwkt_default_replyport;
174 * Similar to the standard initport, this function simply marks the message
175 * as being done and does not attempt to return it to an originating port.
177 void
178 lwkt_initport_null_rport(lwkt_port_t port, thread_t td)
180 lwkt_initport(port, td);
181 port->mp_replyport = lwkt_null_replyport;
185 * lwkt_getport()
187 * Retrieve the next message from the port's message queue, return NULL
188 * if no messages are pending. The retrieved message will either be a
189 * request or a reply based on the MSGF_REPLY bit.
191 * The calling thread MUST own the port.
194 static __inline
195 void
196 _lwkt_pullmsg(lwkt_port_t port, lwkt_msg_t msg)
199 * normal case, remove and return the message.
201 TAILQ_REMOVE(&port->mp_msgq, msg, ms_node);
202 msg->ms_flags &= ~MSGF_QUEUED;
205 void *
206 lwkt_getport(lwkt_port_t port)
208 lwkt_msg_t msg;
210 KKASSERT(port->mp_td == curthread);
212 crit_enter_quick(port->mp_td);
213 if ((msg = TAILQ_FIRST(&port->mp_msgq)) != NULL)
214 _lwkt_pullmsg(port, msg);
215 crit_exit_quick(port->mp_td);
216 return(msg);
219 #ifdef SMP
222 * This function completes reply processing for the default case in the
223 * context of the originating cpu.
225 static
226 void
227 lwkt_replyport_remote(lwkt_msg_t msg)
229 lwkt_port_t port = msg->ms_reply_port;
231 #ifdef INVARIANTS
232 KKASSERT(msg->ms_flags & MSGF_INTRANSIT);
233 msg->ms_flags &= ~MSGF_INTRANSIT;
234 #endif
235 TAILQ_INSERT_TAIL(&port->mp_msgq, msg, ms_node);
236 msg->ms_flags |= MSGF_REPLY | MSGF_DONE | MSGF_QUEUED;
237 if (port->mp_flags & MSGPORTF_WAITING)
238 lwkt_schedule(port->mp_td);
241 #endif
244 * lwkt_default_replyport() - Backend to lwkt_replymsg()
246 * Called with the reply port as an argument but in the context of the
247 * original target port.
249 * The critical section protects us from IPIs on the this CPU.
251 void
252 lwkt_default_replyport(lwkt_port_t port, lwkt_msg_t msg)
254 KKASSERT((msg->ms_flags & (MSGF_DONE|MSGF_QUEUED)) == 0);
256 crit_enter();
257 if (msg->ms_flags & MSGF_SYNC) {
259 * If a synchronous completion has been requested, just wakeup
260 * the message without bothering to queue it to the target port.
262 msg->ms_flags |= MSGF_DONE | MSGF_REPLY;
263 if (port->mp_flags & MSGPORTF_WAITING)
264 lwkt_schedule(port->mp_td);
265 } else {
267 * If an asynchronous completion has been requested the message
268 * must be queued to the reply port. MSGF_REPLY cannot be set
269 * until the message actually gets queued.
271 #ifdef SMP
272 if (port->mp_td->td_gd == mycpu) {
273 #endif
274 TAILQ_INSERT_TAIL(&port->mp_msgq, msg, ms_node);
275 msg->ms_flags |= MSGF_REPLY | MSGF_DONE | MSGF_QUEUED;
276 if (port->mp_flags & MSGPORTF_WAITING)
277 lwkt_schedule(port->mp_td);
278 #ifdef SMP
279 } else {
280 #ifdef INVARIANTS
281 msg->ms_flags |= MSGF_INTRANSIT;
282 #endif
283 msg->ms_flags |= MSGF_REPLY;
284 lwkt_send_ipiq(port->mp_td->td_gd,
285 (ipifunc1_t)lwkt_replyport_remote, msg);
287 #endif
289 crit_exit();
293 * You can point a port's reply vector at this function if you just want
294 * the message marked done, without any queueing or signaling. This is
295 * often used for structure-embedded messages.
297 void
298 lwkt_null_replyport(lwkt_port_t port, lwkt_msg_t msg)
300 msg->ms_flags |= MSGF_DONE | MSGF_REPLY;
304 * lwkt_default_putport() - Backend to lwkt_beginmsg()
306 * Called with the target port as an argument but in the context of the
307 * reply port. This function always implements an asynchronous put to
308 * the target message port, and thus returns EASYNC.
310 * The message must already have cleared MSGF_DONE and MSGF_REPLY
313 #ifdef SMP
315 static
316 void
317 lwkt_putport_remote(lwkt_msg_t msg)
319 lwkt_port_t port = msg->ms_target_port;
321 #ifdef INVARIANTS
322 KKASSERT(msg->ms_flags & MSGF_INTRANSIT);
323 msg->ms_flags &= ~MSGF_INTRANSIT;
324 #endif
325 TAILQ_INSERT_TAIL(&port->mp_msgq, msg, ms_node);
326 msg->ms_flags |= MSGF_QUEUED;
327 if (port->mp_flags & MSGPORTF_WAITING)
328 lwkt_schedule(port->mp_td);
331 #endif
334 lwkt_default_putport(lwkt_port_t port, lwkt_msg_t msg)
336 KKASSERT((msg->ms_flags & (MSGF_DONE | MSGF_REPLY)) == 0);
338 msg->ms_target_port = port;
339 crit_enter();
340 #ifdef SMP
341 if (port->mp_td->td_gd == mycpu) {
342 #endif
343 msg->ms_flags |= MSGF_QUEUED;
344 TAILQ_INSERT_TAIL(&port->mp_msgq, msg, ms_node);
345 if (port->mp_flags & MSGPORTF_WAITING)
346 lwkt_schedule(port->mp_td);
347 #ifdef SMP
348 } else {
349 #ifdef INVARIANTS
350 msg->ms_flags |= MSGF_INTRANSIT;
351 #endif
352 lwkt_send_ipiq(port->mp_td->td_gd,
353 (ipifunc1_t)lwkt_putport_remote, msg);
355 #endif
356 crit_exit();
357 return (EASYNC);
361 * lwkt_forwardmsg()
363 * Forward a message received on one port to another port.
366 lwkt_forwardmsg(lwkt_port_t port, lwkt_msg_t msg)
368 int error;
370 crit_enter();
371 KKASSERT((msg->ms_flags & (MSGF_QUEUED|MSGF_DONE|MSGF_REPLY)) == 0);
372 if ((error = port->mp_putport(port, msg)) != EASYNC)
373 lwkt_replymsg(msg, error);
374 crit_exit();
375 return(error);
379 * lwkt_abortmsg()
381 * Attempt to abort a message. This only works if MSGF_ABORTABLE is set.
382 * The caller must ensure that the message will not be both replied AND
383 * destroyed while the abort is in progress.
385 * This function issues a callback which might block!
388 void
389 lwkt_abortmsg(lwkt_msg_t msg)
392 * A critical section protects us from reply IPIs on this cpu.
394 crit_enter();
397 * Shortcut the operation if the message has already been returned.
398 * The callback typically constructs a lwkt_msg with the abort request,
399 * issues it synchronously, and waits for completion. The callback
400 * is not required to actually abort the message and the target port,
401 * upon receiving an abort request message generated by the callback
402 * should check whether the original message has already completed or
403 * not.
405 if (msg->ms_flags & MSGF_ABORTABLE) {
406 if ((msg->ms_flags & (MSGF_DONE|MSGF_REPLY)) == 0)
407 msg->ms_abortfn(msg);
409 crit_exit();
413 * lwkt_default_waitport()
415 * If msg is NULL, dequeue the next message from the port's message
416 * queue, block until a message is ready. This function never
417 * returns NULL.
419 * If msg is non-NULL, block until the requested message has been
420 * replied, then dequeue and return it.
422 * NOTE: This function should not be used to wait for specific
423 * incoming requests because MSGF_DONE only applies to replies.
425 * Note that the API does not currently support multiple threads waiting
426 * on a single port. The port must be owned by the caller.
428 void *
429 lwkt_default_waitport(lwkt_port_t port, lwkt_msg_t msg)
431 thread_t td = curthread;
432 int sentabort;
434 KKASSERT(port->mp_td == td);
435 crit_enter_quick(td);
436 if (msg == NULL) {
438 * Wait for any message
440 if ((msg = TAILQ_FIRST(&port->mp_msgq)) == NULL) {
441 port->mp_flags |= MSGPORTF_WAITING;
442 td->td_flags |= TDF_BLOCKED;
443 do {
444 lwkt_deschedule_self(td);
445 lwkt_switch();
446 } while ((msg = TAILQ_FIRST(&port->mp_msgq)) == NULL);
447 td->td_flags &= ~TDF_BLOCKED;
448 port->mp_flags &= ~MSGPORTF_WAITING;
450 _lwkt_pullmsg(port, msg);
451 } else {
453 * Wait for a specific message.
455 KKASSERT(msg->ms_reply_port == port);
456 if ((msg->ms_flags & MSGF_DONE) == 0) {
457 sentabort = 0;
458 while ((msg->ms_flags & MSGF_DONE) == 0) {
460 * MSGF_PCATCH is only set by processes which wish to
461 * abort the message they are blocked on when a signal
462 * occurs. Note that we still must wait for message
463 * completion after sending an abort request.
465 if (msg->ms_flags & MSGF_PCATCH) {
466 if (sentabort == 0 && CURSIG(port->mp_td->td_lwp)) {
467 sentabort = 1;
468 lwkt_abortmsg(msg);
469 continue;
474 * XXX set TDF_SINTR so 'ps' knows the difference between
475 * an interruptable wait and a disk wait. YYY eventually
476 * move LWP_SINTR to TDF_SINTR to reduce duplication.
478 port->mp_flags |= MSGPORTF_WAITING;
479 td->td_flags |= TDF_SINTR | TDF_BLOCKED;
480 lwkt_deschedule_self(td);
481 lwkt_switch();
482 td->td_flags &= ~(TDF_SINTR | TDF_BLOCKED);
483 port->mp_flags &= ~MSGPORTF_WAITING;
488 * Once the MSGF_DONE bit is set, the message is stable. We
489 * can just check MSGF_QUEUED to determine
491 if (msg->ms_flags & MSGF_QUEUED) {
492 msg->ms_flags &= ~MSGF_QUEUED;
493 TAILQ_REMOVE(&port->mp_msgq, msg, ms_node);
496 crit_exit_quick(td);
497 return(msg);