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: 10 * 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. 20 * 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. 33 * 34 * NOTE! This file may be compiled for userland libraries as well as for 35 * the kernel. 36 * 37 * $DragonFly: src/sys/kern/lwkt_msgport.c,v 1.30 2004/09/10 18:23:55 dillon Exp $ 38 */ 39 40 #ifdef _KERNEL 41 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 <machine/cpu.h> 52 #include <sys/lock.h> 53 54 #include <vm/vm.h> 55 #include <vm/vm_param.h> 56 #include <vm/vm_kern.h> 57 #include <vm/vm_object.h> 58 #include <vm/vm_page.h> 59 #include <vm/vm_map.h> 60 #include <vm/vm_pager.h> 61 #include <vm/vm_extern.h> 62 #include <vm/vm_zone.h> 63 64 #include <sys/thread2.h> 65 #include <sys/msgport2.h> 66 67 #include <machine/stdarg.h> 68 #include <machine/ipl.h> 69 #include <machine/cpufunc.h> 70 #ifdef SMP 71 #include <machine/smp.h> 72 #endif 73 74 #include <sys/malloc.h> 75 MALLOC_DEFINE(M_LWKTMSG, "lwkt message", "lwkt message"); 76 77 #else 78 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> 89 90 #endif /* _KERNEL */ 91 92 93 /************************************************************************ 94 * MESSAGE FUNCTIONS * 95 ************************************************************************/ 96 97 static void lwkt_replyport_remote(lwkt_msg_t msg); 98 static void lwkt_putport_remote(lwkt_msg_t msg); 99 100 /* 101 * lwkt_sendmsg() 102 * 103 * Send a message asynchronously. This function requests asynchronous 104 * completion and calls lwkt_beginmsg(). If the target port decides to 105 * run the message synchronously this function will automatically queue 106 * the message to the current thread's message queue to present a 107 * consistent interface to the caller. 108 * 109 * The message's ms_cmd must be initialized and its ms_flags must 110 * be zero'd out. lwkt_sendmsg() will initialize the ms_abort_port 111 * (abort chasing port). If abort is supported, ms_abort must also be 112 * initialized. 113 * 114 * NOTE: you cannot safely request an abort until lwkt_sendmsg() returns 115 * to the caller. 116 * 117 * NOTE: MSGF_DONE is left set. The target port must clear it if the 118 * message is to be handled asynchronously, while the synchronous case 119 * can just ignore it. 120 */ 121 void 122 lwkt_sendmsg(lwkt_port_t port, lwkt_msg_t msg) 123 { 124 int error; 125 126 msg->ms_flags |= MSGF_ASYNC; 127 msg->ms_flags &= ~(MSGF_REPLY1 | MSGF_REPLY2 | MSGF_QUEUED | \ 128 MSGF_ABORTED | MSGF_RETRIEVED); 129 KKASSERT(msg->ms_reply_port != NULL); 130 msg->ms_abort_port = msg->ms_reply_port; 131 if ((error = lwkt_beginmsg(port, msg)) != EASYNC) { 132 lwkt_replymsg(msg, error); 133 } 134 } 135 136 /* 137 * lwkt_domsg() 138 * 139 * Send a message synchronously. This function requests synchronous 140 * completion and calls lwkt_beginmsg(). If the target port decides to 141 * run the message asynchronously this function will block waiting for 142 * the message to complete. Since MSGF_ASYNC is not set the target 143 * will not attempt to queue the reply to a reply port but will simply 144 * wake up anyone waiting on the message. 145 * 146 * A synchronous error code is always returned. 147 * 148 * The message's ms_cmd must be initialized, and its ms_flags must be 149 * at least zero'd out. lwkt_domsg() will initialize the message's 150 * ms_abort_port (abort chasing port). If abort is supported, ms_abort 151 * must also be initialized. 152 * 153 * NOTE: you cannot safely request an abort until lwkt_domsg() blocks. 154 * XXX this probably needs some work. 155 * 156 * NOTE: MSGF_DONE is left set. The target port must clear it if the 157 * message is to be handled asynchronously, while the synchronous case 158 * can just ignore it. 159 */ 160 int 161 lwkt_domsg(lwkt_port_t port, lwkt_msg_t msg) 162 { 163 int error; 164 165 msg->ms_flags &= ~(MSGF_ASYNC | MSGF_REPLY1 | MSGF_REPLY2 | \ 166 MSGF_QUEUED | MSGF_ABORTED | MSGF_RETRIEVED); 167 KKASSERT(msg->ms_reply_port != NULL); 168 msg->ms_abort_port = msg->ms_reply_port; 169 if ((error = lwkt_beginmsg(port, msg)) == EASYNC) { 170 error = lwkt_waitmsg(msg); 171 } 172 return(error); 173 } 174 175 /************************************************************************ 176 * PORT FUNCTIONS * 177 ************************************************************************/ 178 179 /* 180 * lwkt_initport() 181 * 182 * Initialize a port for use and assign it to the specified thread. 183 */ 184 void 185 lwkt_initport(lwkt_port_t port, thread_t td) 186 { 187 bzero(port, sizeof(*port)); 188 TAILQ_INIT(&port->mp_msgq); 189 port->mp_td = td; 190 port->mp_putport = lwkt_default_putport; 191 port->mp_waitport = lwkt_default_waitport; 192 port->mp_replyport = lwkt_default_replyport; 193 port->mp_abortport = lwkt_default_abortport; 194 } 195 196 void 197 lwkt_initport_null_rport(lwkt_port_t port, thread_t td) 198 { 199 lwkt_initport(port, td); 200 port->mp_replyport = lwkt_null_replyport; 201 } 202 203 /* 204 * lwkt_getport() 205 * 206 * Retrieve the next message from the port's message queue, return NULL 207 * if no messages are pending. Note that callers CANNOT use the 208 * MSGF_ABORTED flag as a litmus test to determine if a message 209 * was aborted. The flag only indicates that an abort was requested. 210 * The message's error code will indicate whether an abort occured 211 * (typically by returning EINTR). 212 * 213 * Note that once a message has been dequeued it is subject to being 214 * requeued via an IPI based abort request if it is not marked MSGF_DONE. 215 * 216 * If the message has been aborted we have to guarentee that abort 217 * semantics are properly followed. The target port will always see 218 * the original message at least once, and if it does not reply the 219 * message before looping on its message port again it will then see 220 * the message again with ms_cmd set to ms_abort. 221 * 222 * The calling thread MUST own the port. 223 */ 224 225 static __inline 226 void 227 _lwkt_pullmsg(lwkt_port_t port, lwkt_msg_t msg) 228 { 229 if ((msg->ms_flags & MSGF_ABORTED) == 0) { 230 /* 231 * normal case, remove and return the message. 232 */ 233 TAILQ_REMOVE(&port->mp_msgq, msg, ms_node); 234 msg->ms_flags = (msg->ms_flags & ~MSGF_QUEUED) | MSGF_RETRIEVED; 235 } else { 236 if (msg->ms_flags & MSGF_RETRIEVED) { 237 /* 238 * abort case, message already returned once, remvoe and 239 * return the aborted message a second time after setting 240 * ms_cmd to ms_abort. 241 */ 242 TAILQ_REMOVE(&port->mp_msgq, msg, ms_node); 243 msg->ms_flags &= ~MSGF_QUEUED; 244 msg->ms_cmd = msg->ms_abort; 245 } else { 246 /* 247 * abort case, abort races initial message retrieval. The 248 * message is returned normally but not removed from the 249 * queue. On the next loop the 'aborted' message will be 250 * dequeued and returned. Note that if the caller replies 251 * to the message it will be dequeued (the abort becomes a 252 * NOP). 253 */ 254 msg->ms_flags |= MSGF_RETRIEVED; 255 } 256 } 257 } 258 259 void * 260 lwkt_getport(lwkt_port_t port) 261 { 262 lwkt_msg_t msg; 263 264 KKASSERT(port->mp_td == curthread); 265 266 crit_enter_quick(port->mp_td); 267 if ((msg = TAILQ_FIRST(&port->mp_msgq)) != NULL) 268 _lwkt_pullmsg(port, msg); 269 crit_exit_quick(port->mp_td); 270 return(msg); 271 } 272 273 /* 274 * This inline helper function completes processing of a reply from an 275 * unknown cpu context. 276 * 277 * The message is being returned to the specified port. The port is 278 * owned by the mp_td thread. If we are on the same cpu as the mp_td 279 * thread we can trivially queue the message to the reply port and schedule 280 * the target thread, otherwise we have to send an ipi message to the 281 * correct cpu. 282 * 283 * This inline must be entered with a critical section already held. 284 * Note that the IPIQ callback function (*_remote) is entered with a 285 * critical section already held, and we obtain one in lwkt_replyport(). 286 */ 287 static __inline 288 void 289 _lwkt_replyport(lwkt_port_t port, lwkt_msg_t msg, int force) 290 { 291 thread_t td = port->mp_td; 292 293 if (force || td->td_gd == mycpu) { 294 /* 295 * We can only reply the message if the abort has caught up with us, 296 * or if no abort was issued (same case). 297 */ 298 if (msg->ms_abort_port == port) { 299 KKASSERT((msg->ms_flags & MSGF_QUEUED) == 0); 300 TAILQ_INSERT_TAIL(&port->mp_msgq, msg, ms_node); 301 msg->ms_flags |= MSGF_DONE | MSGF_QUEUED | MSGF_REPLY2; 302 if (port->mp_flags & MSGPORTF_WAITING) 303 lwkt_schedule(td); 304 } 305 } else { 306 lwkt_send_ipiq(td->td_gd, (ipifunc_t)lwkt_replyport_remote, msg); 307 } 308 } 309 310 /* 311 * This function completes reply processing for the default case in the 312 * context of the originating cpu. 313 */ 314 static 315 void 316 lwkt_replyport_remote(lwkt_msg_t msg) 317 { 318 _lwkt_replyport(msg->ms_reply_port, msg, 1); 319 } 320 321 /* 322 * This function is called in the context of the target to reply a message. 323 * The critical section protects us from IPIs on the this CPU. 324 */ 325 void 326 lwkt_default_replyport(lwkt_port_t port, lwkt_msg_t msg) 327 { 328 crit_enter(); 329 msg->ms_flags |= MSGF_REPLY1; 330 331 /* 332 * An abort may have caught up to us while we were processing the 333 * message. If this occured we have to dequeue the message from the 334 * target port in the context of our current cpu before we can finish 335 * replying it. 336 */ 337 if (msg->ms_flags & MSGF_QUEUED) { 338 KKASSERT(msg->ms_flags & MSGF_ABORTED); 339 TAILQ_REMOVE(&msg->ms_target_port->mp_msgq, msg, ms_node); 340 msg->ms_flags &= ~MSGF_QUEUED; 341 } 342 343 /* 344 * Do reply port processing for async messages. Just mark the message 345 * done and wakeup the owner of the reply port for synchronous messages. 346 */ 347 if (msg->ms_flags & MSGF_ASYNC) { 348 _lwkt_replyport(port, msg, 0); 349 } else { 350 msg->ms_flags |= MSGF_DONE; 351 if (port->mp_flags & MSGPORTF_WAITING) 352 lwkt_schedule(port->mp_td); 353 } 354 crit_exit(); 355 } 356 357 /* 358 * You can point a port's reply vector at this function if you just want 359 * the message marked done, without any queueing or signaling. This is 360 * often used for structure-embedded messages. 361 */ 362 void 363 lwkt_null_replyport(lwkt_port_t port, lwkt_msg_t msg) 364 { 365 crit_enter(); 366 msg->ms_flags |= MSGF_DONE|MSGF_REPLY1; 367 crit_exit(); 368 } 369 370 /* 371 * lwkt_default_putport() 372 * 373 * This function is typically assigned to the mp_putport port vector. 374 * 375 * Queue a message to the target port and wakeup the thread owning it. 376 * This function always returns EASYNC and may be assigned to a 377 * message port's mp_putport function vector. Note that we must set 378 * MSGF_QUEUED prior to sending any IPIs in order to interlock against 379 * ABORT requests and other tests that might be performed. 380 * 381 * Note that messages start out as synchronous entities, and as an 382 * optimization MSGF_DONE is usually left set (so in the synchronous path 383 * no modifications to ms_flags are ever required). If a message becomes 384 * async, i.e. you return EASYNC, then MSGF_DONE must be cleared or 385 * lwkt_replymsg() will wind up being a NOP. 386 * 387 * The inline must be called from a critical section (the remote function 388 * is called from an IPI and will be in a critical section). 389 */ 390 static 391 __inline 392 void 393 _lwkt_putport(lwkt_port_t port, lwkt_msg_t msg, int force) 394 { 395 thread_t td = port->mp_td; 396 397 if (force || td->td_gd == mycpu) { 398 TAILQ_INSERT_TAIL(&port->mp_msgq, msg, ms_node); 399 if (port->mp_flags & MSGPORTF_WAITING) 400 lwkt_schedule(td); 401 } else { 402 lwkt_send_ipiq(td->td_gd, (ipifunc_t)lwkt_putport_remote, msg); 403 } 404 } 405 406 static 407 void 408 lwkt_putport_remote(lwkt_msg_t msg) 409 { 410 _lwkt_putport(msg->ms_target_port, msg, 1); 411 } 412 413 int 414 lwkt_default_putport(lwkt_port_t port, lwkt_msg_t msg) 415 { 416 crit_enter(); 417 msg->ms_flags |= MSGF_QUEUED; /* abort interlock */ 418 msg->ms_flags &= ~MSGF_DONE; 419 msg->ms_target_port = port; 420 _lwkt_putport(port, msg, 0); 421 crit_exit(); 422 return(EASYNC); 423 } 424 425 /* 426 * lwkt_forwardmsg() 427 * 428 * Forward a message received on one port to another port. The forwarding 429 * function must deal with a pending abort but othewise essentially just 430 * issues a putport to the target port. 431 * 432 * An abort may have two side effects: First, the message may have been 433 * requeued to the current target port. If so, we must dequeue it before 434 * we can forward it. 435 */ 436 int 437 lwkt_forwardmsg(lwkt_port_t port, lwkt_msg_t msg) 438 { 439 int error; 440 441 crit_enter(); 442 if (msg->ms_flags & MSGF_QUEUED) { 443 KKASSERT(msg->ms_flags & MSGF_ABORTED); 444 TAILQ_REMOVE(&msg->ms_target_port->mp_msgq, msg, ms_node); 445 msg->ms_flags &= ~MSGF_QUEUED; 446 } 447 msg->ms_flags &= ~MSGF_RETRIEVED; 448 if ((error = port->mp_putport(port, msg)) != EASYNC) 449 lwkt_replymsg(msg, error); 450 crit_exit(); 451 return(error); 452 } 453 454 /* 455 * lwkt_abortmsg() 456 * 457 * Aborting a message is a fairly complex task. The first order of 458 * business is to get the message to the cpu that owns the target 459 * port, during which we may have to do some port chasing due to 460 * message forwarding operations. 461 * 462 * NOTE! Since an aborted message is requeued all message processing 463 * loops should check the MSGF_ABORTED flag. 464 */ 465 static void lwkt_abortmsg_remote(lwkt_msg_t msg); 466 467 void 468 lwkt_abortmsg(lwkt_msg_t msg) 469 { 470 lwkt_port_t port; 471 thread_t td; 472 473 /* 474 * A critical section protects us from reply IPIs on this cpu. We 475 * can only abort messages that have not yet completed (DONE), are not 476 * in the midst of being replied (REPLY1), and which support the 477 * abort function (ABORTABLE). 478 */ 479 crit_enter(); 480 if ((msg->ms_flags & (MSGF_DONE|MSGF_REPLY1|MSGF_ABORTABLE)) == MSGF_ABORTABLE) { 481 /* 482 * Chase the message. If REPLY1 is set the message has been replied 483 * all the way back to the originator, otherwise it is sitting on 484 * ms_target_port (but we can only complete processing if we are 485 * on the same cpu as the selected port in order to avoid 486 * SMP cache synchronization issues). 487 * 488 * When chasing through multiple ports ms_flags may not be 489 * synchronized to the current cpu, but it WILL be synchronized 490 * with regards to testing the MSGF_REPLY1 bit once we reach the 491 * target port that made the reply and since the cpu owning 492 * some port X stores the new port in ms_target_port if the message 493 * is forwarded, the current port will only ever equal the target 494 * port when we are on the correct cpu. 495 */ 496 if (msg->ms_flags & MSGF_REPLY1) 497 port = msg->ms_reply_port; 498 else 499 port = msg->ms_target_port; 500 cpu_mb1(); 501 502 /* 503 * The chase call must run on the cpu owning the port. Fully 504 * synchronous ports (mp_td == NULL) can run the call on any cpu. 505 */ 506 td = port->mp_td; 507 if (td && td->td_gd != mycpu) { 508 lwkt_send_ipiq(td->td_gd, (ipifunc_t)lwkt_abortmsg_remote, msg); 509 } else { 510 port->mp_abortport(port, msg); 511 } 512 } 513 crit_exit(); 514 } 515 516 static 517 void 518 lwkt_abortmsg_remote(lwkt_msg_t msg) 519 { 520 lwkt_port_t port; 521 thread_t td; 522 523 if (msg->ms_flags & MSGF_REPLY1) 524 port = msg->ms_reply_port; 525 else 526 port = msg->ms_target_port; 527 cpu_mb1(); 528 td = port->mp_td; 529 if (td->td_gd != mycpu) { 530 lwkt_send_ipiq(td->td_gd, (ipifunc_t)lwkt_abortmsg_remote, msg); 531 } else { 532 port->mp_abortport(port, msg); 533 } 534 } 535 536 /* 537 * The mp_abortport function is called when the abort has finally caught up 538 * to the target port or (if the message has been replied) the reply port. 539 */ 540 void 541 lwkt_default_abortport(lwkt_port_t port, lwkt_msg_t msg) 542 { 543 /* 544 * Set ms_abort_port to ms_reply_port to indicate the completion of 545 * the messaging chasing portion of the abort request. Note that 546 * the passed port is the port that we finally caught up to, not 547 * necessarily the reply port. 548 */ 549 msg->ms_abort_port = msg->ms_reply_port; 550 551 if (msg->ms_flags & MSGF_REPLY2) { 552 /* 553 * If REPLY2 is set we must have chased it all the way back to 554 * the reply port, but the replyport code has not queued the message 555 * (because it was waiting for the abort to catch up). We become 556 * responsible for queueing the message to the reply port. 557 */ 558 KKASSERT((msg->ms_flags & MSGF_QUEUED) == 0); 559 KKASSERT(port == msg->ms_reply_port); 560 TAILQ_INSERT_TAIL(&port->mp_msgq, msg, ms_node); 561 msg->ms_flags |= MSGF_DONE | MSGF_QUEUED; 562 if (port->mp_flags & MSGPORTF_WAITING) 563 lwkt_schedule(port->mp_td); 564 } else if ((msg->ms_flags & (MSGF_QUEUED|MSGF_REPLY1)) == 0) { 565 /* 566 * Abort on the target port. The message has not yet been replied 567 * and must be requeued to the target port. 568 */ 569 msg->ms_flags |= MSGF_ABORTED | MSGF_QUEUED; 570 TAILQ_INSERT_TAIL(&port->mp_msgq, msg, ms_node); 571 if (port->mp_flags & MSGPORTF_WAITING) 572 lwkt_schedule(port->mp_td); 573 } else if ((msg->ms_flags & MSGF_REPLY1) == 0) { 574 /* 575 * The message has not yet been retrieved by the target port, set 576 * MSGF_ABORTED so the target port can requeue the message abort after 577 * retrieving it. 578 */ 579 msg->ms_flags |= MSGF_ABORTED; 580 } 581 } 582 583 /* 584 * lwkt_default_waitport() 585 * 586 * If msg is NULL, dequeue the next message from the port's message 587 * queue, block until a message is ready. This function never 588 * returns NULL. 589 * 590 * If msg is non-NULL, block until the requested message has been returned 591 * to the port then dequeue and return it. DO NOT USE THIS TO WAIT FOR 592 * INCOMING REQUESTS, ONLY USE THIS TO WAIT FOR REPLIES. 593 * 594 * Note that the API does not currently support multiple threads waiting 595 * on a port. By virtue of owning the port it is controlled by our 596 * cpu and we can safely manipulate it's contents. 597 */ 598 void * 599 lwkt_default_waitport(lwkt_port_t port, lwkt_msg_t msg) 600 { 601 thread_t td = curthread; 602 int sentabort; 603 604 KKASSERT(port->mp_td == td); 605 crit_enter_quick(td); 606 if (msg == NULL) { 607 if ((msg = TAILQ_FIRST(&port->mp_msgq)) == NULL) { 608 port->mp_flags |= MSGPORTF_WAITING; 609 td->td_flags |= TDF_BLOCKED; 610 do { 611 lwkt_deschedule_self(td); 612 lwkt_switch(); 613 } while ((msg = TAILQ_FIRST(&port->mp_msgq)) == NULL); 614 td->td_flags &= ~TDF_BLOCKED; 615 port->mp_flags &= ~MSGPORTF_WAITING; 616 } 617 _lwkt_pullmsg(port, msg); 618 } else { 619 /* 620 * If a message is not marked done, or if it is queued, we have work 621 * to do. Note that MSGF_DONE is always set in the context of the 622 * reply port's cpu. 623 */ 624 if ((msg->ms_flags & (MSGF_DONE|MSGF_QUEUED)) != MSGF_DONE) { 625 /* 626 * We must own the reply port to safely mess with it's contents. 627 */ 628 port = msg->ms_reply_port; 629 KKASSERT(port->mp_td == td); 630 631 if ((msg->ms_flags & MSGF_DONE) == 0) { 632 port->mp_flags |= MSGPORTF_WAITING; /* saved by the BGL */ 633 sentabort = 0; 634 do { 635 #ifdef _KERNEL 636 /* 637 * MSGF_PCATCH is only set by processes which wish to 638 * abort the message they are blocked on when a signal 639 * occurs. Note that we still must wait for message 640 * completion after sending an abort request. 641 */ 642 if (msg->ms_flags & MSGF_PCATCH) { 643 if (sentabort == 0 && CURSIG(port->mp_td->td_proc)) { 644 sentabort = 1; 645 lwkt_abortmsg(msg); 646 continue; 647 } 648 } 649 #endif 650 /* 651 * XXX set TDF_SINTR so 'ps' knows the difference between 652 * an interruptable wait and a disk wait. YYY eventually 653 * move P_SINTR to TDF_SINTR to reduce duplication. 654 */ 655 td->td_flags |= TDF_SINTR | TDF_BLOCKED; 656 lwkt_deschedule_self(td); 657 lwkt_switch(); 658 td->td_flags &= ~(TDF_SINTR | TDF_BLOCKED); 659 } while ((msg->ms_flags & MSGF_DONE) == 0); 660 port->mp_flags &= ~MSGPORTF_WAITING; /* saved by the BGL */ 661 } 662 /* 663 * We own the message now. 664 */ 665 if (msg->ms_flags & MSGF_QUEUED) { 666 msg->ms_flags &= ~MSGF_QUEUED; 667 TAILQ_REMOVE(&port->mp_msgq, msg, ms_node); 668 } 669 } 670 } 671 crit_exit_quick(td); 672 return(msg); 673 } 674 675