subr_sleepqueue.c (176258) | subr_sleepqueue.c (177085) |
---|---|
1/*- 2 * Copyright (c) 2004 John Baldwin <jhb@FreeBSD.org> 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 --- 46 unchanged lines hidden (view full) --- 55 * must consistently use the same lock to synchronize with a wait channel, 56 * though this check is currently only a warning for sleep/wakeup due to 57 * pre-existing abuse of that API. The same lock must also be held when 58 * awakening threads, though that is currently only enforced for condition 59 * variables. 60 */ 61 62#include <sys/cdefs.h> | 1/*- 2 * Copyright (c) 2004 John Baldwin <jhb@FreeBSD.org> 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 --- 46 unchanged lines hidden (view full) --- 55 * must consistently use the same lock to synchronize with a wait channel, 56 * though this check is currently only a warning for sleep/wakeup due to 57 * pre-existing abuse of that API. The same lock must also be held when 58 * awakening threads, though that is currently only enforced for condition 59 * variables. 60 */ 61 62#include <sys/cdefs.h> |
63__FBSDID("$FreeBSD: head/sys/kern/subr_sleepqueue.c 176258 2008-02-13 23:36:56Z jhb $"); | 63__FBSDID("$FreeBSD: head/sys/kern/subr_sleepqueue.c 177085 2008-03-12 06:31:06Z jeff $"); |
64 65#include "opt_sleepqueue_profiling.h" 66#include "opt_ddb.h" 67#include "opt_sched.h" 68 69#include <sys/param.h> 70#include <sys/systm.h> 71#include <sys/lock.h> --- 72 unchanged lines hidden (view full) --- 144 0, "maxmimum depth achieved of a single chain"); 145#endif 146static struct sleepqueue_chain sleepq_chains[SC_TABLESIZE]; 147static uma_zone_t sleepq_zone; 148 149/* 150 * Prototypes for non-exported routines. 151 */ | 64 65#include "opt_sleepqueue_profiling.h" 66#include "opt_ddb.h" 67#include "opt_sched.h" 68 69#include <sys/param.h> 70#include <sys/systm.h> 71#include <sys/lock.h> --- 72 unchanged lines hidden (view full) --- 144 0, "maxmimum depth achieved of a single chain"); 145#endif 146static struct sleepqueue_chain sleepq_chains[SC_TABLESIZE]; 147static uma_zone_t sleepq_zone; 148 149/* 150 * Prototypes for non-exported routines. 151 */ |
152static int sleepq_catch_signals(void *wchan); | 152static int sleepq_catch_signals(void *wchan, int pri); |
153static int sleepq_check_signals(void); 154static int sleepq_check_timeout(void); 155#ifdef INVARIANTS 156static void sleepq_dtor(void *mem, int size, void *arg); 157#endif 158static int sleepq_init(void *mem, int size, int flags); 159static void sleepq_resume_thread(struct sleepqueue *sq, struct thread *td, 160 int pri); | 153static int sleepq_check_signals(void); 154static int sleepq_check_timeout(void); 155#ifdef INVARIANTS 156static void sleepq_dtor(void *mem, int size, void *arg); 157#endif 158static int sleepq_init(void *mem, int size, int flags); 159static void sleepq_resume_thread(struct sleepqueue *sq, struct thread *td, 160 int pri); |
161static void sleepq_switch(void *wchan); | 161static void sleepq_switch(void *wchan, int pri); |
162static void sleepq_timeout(void *arg); 163 164/* 165 * Early initialization of sleep queues that is called from the sleepinit() 166 * SYSINIT. 167 */ 168void 169init_sleepqueues(void) --- 192 unchanged lines hidden (view full) --- 362 363/* 364 * Marks the pending sleep of the current thread as interruptible and 365 * makes an initial check for pending signals before putting a thread 366 * to sleep. Enters and exits with the thread lock held. Thread lock 367 * may have transitioned from the sleepq lock to a run lock. 368 */ 369static int | 162static void sleepq_timeout(void *arg); 163 164/* 165 * Early initialization of sleep queues that is called from the sleepinit() 166 * SYSINIT. 167 */ 168void 169init_sleepqueues(void) --- 192 unchanged lines hidden (view full) --- 362 363/* 364 * Marks the pending sleep of the current thread as interruptible and 365 * makes an initial check for pending signals before putting a thread 366 * to sleep. Enters and exits with the thread lock held. Thread lock 367 * may have transitioned from the sleepq lock to a run lock. 368 */ 369static int |
370sleepq_catch_signals(void *wchan) | 370sleepq_catch_signals(void *wchan, int pri) |
371{ 372 struct sleepqueue_chain *sc; 373 struct sleepqueue *sq; 374 struct thread *td; 375 struct proc *p; 376 struct sigacts *ps; 377 int sig, ret; 378 --- 27 unchanged lines hidden (view full) --- 406 * Lock sleepq chain before unlocking proc 407 * without this, we could lose a race. 408 */ 409 mtx_lock_spin(&sc->sc_lock); 410 PROC_UNLOCK(p); 411 thread_lock(td); 412 if (ret == 0) { 413 if (!(td->td_flags & TDF_INTERRUPT)) { | 371{ 372 struct sleepqueue_chain *sc; 373 struct sleepqueue *sq; 374 struct thread *td; 375 struct proc *p; 376 struct sigacts *ps; 377 int sig, ret; 378 --- 27 unchanged lines hidden (view full) --- 406 * Lock sleepq chain before unlocking proc 407 * without this, we could lose a race. 408 */ 409 mtx_lock_spin(&sc->sc_lock); 410 PROC_UNLOCK(p); 411 thread_lock(td); 412 if (ret == 0) { 413 if (!(td->td_flags & TDF_INTERRUPT)) { |
414 sleepq_switch(wchan); | 414 sleepq_switch(wchan, pri); |
415 return (0); 416 } 417 /* KSE threads tried unblocking us. */ 418 ret = td->td_intrval; 419 MPASS(ret == EINTR || ret == ERESTART || ret == EWOULDBLOCK); 420 } 421 /* 422 * There were pending signals and this thread is still 423 * on the sleep queue, remove it from the sleep queue. 424 */ 425 if (TD_ON_SLEEPQ(td)) { 426 sq = sleepq_lookup(wchan); | 415 return (0); 416 } 417 /* KSE threads tried unblocking us. */ 418 ret = td->td_intrval; 419 MPASS(ret == EINTR || ret == ERESTART || ret == EWOULDBLOCK); 420 } 421 /* 422 * There were pending signals and this thread is still 423 * on the sleep queue, remove it from the sleep queue. 424 */ 425 if (TD_ON_SLEEPQ(td)) { 426 sq = sleepq_lookup(wchan); |
427 sleepq_resume_thread(sq, td, -1); | 427 sleepq_resume_thread(sq, td, 0); |
428 } 429 mtx_unlock_spin(&sc->sc_lock); 430 MPASS(td->td_lock != &sc->sc_lock); 431 return (ret); 432} 433 434/* 435 * Switches to another thread if we are still asleep on a sleep queue. 436 * Returns with thread lock. 437 */ 438static void | 428 } 429 mtx_unlock_spin(&sc->sc_lock); 430 MPASS(td->td_lock != &sc->sc_lock); 431 return (ret); 432} 433 434/* 435 * Switches to another thread if we are still asleep on a sleep queue. 436 * Returns with thread lock. 437 */ 438static void |
439sleepq_switch(void *wchan) | 439sleepq_switch(void *wchan, int pri) |
440{ 441 struct sleepqueue_chain *sc; 442 struct sleepqueue *sq; 443 struct thread *td; 444 445 td = curthread; 446 sc = SC_LOOKUP(wchan); 447 mtx_assert(&sc->sc_lock, MA_OWNED); --- 11 unchanged lines hidden (view full) --- 459 /* 460 * If TDF_TIMEOUT is set, then our sleep has been timed out 461 * already but we are still on the sleep queue, so dequeue the 462 * thread and return. 463 */ 464 if (td->td_flags & TDF_TIMEOUT) { 465 MPASS(TD_ON_SLEEPQ(td)); 466 sq = sleepq_lookup(wchan); | 440{ 441 struct sleepqueue_chain *sc; 442 struct sleepqueue *sq; 443 struct thread *td; 444 445 td = curthread; 446 sc = SC_LOOKUP(wchan); 447 mtx_assert(&sc->sc_lock, MA_OWNED); --- 11 unchanged lines hidden (view full) --- 459 /* 460 * If TDF_TIMEOUT is set, then our sleep has been timed out 461 * already but we are still on the sleep queue, so dequeue the 462 * thread and return. 463 */ 464 if (td->td_flags & TDF_TIMEOUT) { 465 MPASS(TD_ON_SLEEPQ(td)); 466 sq = sleepq_lookup(wchan); |
467 sleepq_resume_thread(sq, td, -1); | 467 sleepq_resume_thread(sq, td, 0); |
468 mtx_unlock_spin(&sc->sc_lock); 469 return; 470 } 471 | 468 mtx_unlock_spin(&sc->sc_lock); 469 return; 470 } 471 |
472 thread_lock_set(td, &sc->sc_lock); 473 | |
474 MPASS(td->td_sleepqueue == NULL); | 472 MPASS(td->td_sleepqueue == NULL); |
475 sched_sleep(td); | 473 sched_sleep(td, pri); 474 thread_lock_set(td, &sc->sc_lock); |
476 TD_SET_SLEEPING(td); 477 SCHED_STAT_INC(switch_sleepq); 478 mi_switch(SW_VOL, NULL); 479 KASSERT(TD_IS_RUNNING(td), ("running but not TDS_RUNNING")); 480 CTR3(KTR_PROC, "sleepq resume: thread %p (pid %ld, %s)", 481 (void *)td, (long)td->td_proc->p_pid, (void *)td->td_name); 482} 483 --- 62 unchanged lines hidden (view full) --- 546 547 return (0); 548} 549 550/* 551 * Block the current thread until it is awakened from its sleep queue. 552 */ 553void | 475 TD_SET_SLEEPING(td); 476 SCHED_STAT_INC(switch_sleepq); 477 mi_switch(SW_VOL, NULL); 478 KASSERT(TD_IS_RUNNING(td), ("running but not TDS_RUNNING")); 479 CTR3(KTR_PROC, "sleepq resume: thread %p (pid %ld, %s)", 480 (void *)td, (long)td->td_proc->p_pid, (void *)td->td_name); 481} 482 --- 62 unchanged lines hidden (view full) --- 545 546 return (0); 547} 548 549/* 550 * Block the current thread until it is awakened from its sleep queue. 551 */ 552void |
554sleepq_wait(void *wchan) | 553sleepq_wait(void *wchan, int pri) |
555{ 556 struct thread *td; 557 558 td = curthread; 559 MPASS(!(td->td_flags & TDF_SINTR)); 560 thread_lock(td); | 554{ 555 struct thread *td; 556 557 td = curthread; 558 MPASS(!(td->td_flags & TDF_SINTR)); 559 thread_lock(td); |
561 sleepq_switch(wchan); | 560 sleepq_switch(wchan, pri); |
562 thread_unlock(td); 563} 564 565/* 566 * Block the current thread until it is awakened from its sleep queue 567 * or it is interrupted by a signal. 568 */ 569int | 561 thread_unlock(td); 562} 563 564/* 565 * Block the current thread until it is awakened from its sleep queue 566 * or it is interrupted by a signal. 567 */ 568int |
570sleepq_wait_sig(void *wchan) | 569sleepq_wait_sig(void *wchan, int pri) |
571{ 572 int rcatch; 573 int rval; 574 | 570{ 571 int rcatch; 572 int rval; 573 |
575 rcatch = sleepq_catch_signals(wchan); | 574 rcatch = sleepq_catch_signals(wchan, pri); |
576 rval = sleepq_check_signals(); 577 thread_unlock(curthread); 578 if (rcatch) 579 return (rcatch); 580 return (rval); 581} 582 583/* 584 * Block the current thread until it is awakened from its sleep queue 585 * or it times out while waiting. 586 */ 587int | 575 rval = sleepq_check_signals(); 576 thread_unlock(curthread); 577 if (rcatch) 578 return (rcatch); 579 return (rval); 580} 581 582/* 583 * Block the current thread until it is awakened from its sleep queue 584 * or it times out while waiting. 585 */ 586int |
588sleepq_timedwait(void *wchan) | 587sleepq_timedwait(void *wchan, int pri) |
589{ 590 struct thread *td; 591 int rval; 592 593 td = curthread; 594 MPASS(!(td->td_flags & TDF_SINTR)); 595 thread_lock(td); | 588{ 589 struct thread *td; 590 int rval; 591 592 td = curthread; 593 MPASS(!(td->td_flags & TDF_SINTR)); 594 thread_lock(td); |
596 sleepq_switch(wchan); | 595 sleepq_switch(wchan, pri); |
597 rval = sleepq_check_timeout(); 598 thread_unlock(td); 599 600 return (rval); 601} 602 603/* 604 * Block the current thread until it is awakened from its sleep queue, 605 * it is interrupted by a signal, or it times out waiting to be awakened. 606 */ 607int | 596 rval = sleepq_check_timeout(); 597 thread_unlock(td); 598 599 return (rval); 600} 601 602/* 603 * Block the current thread until it is awakened from its sleep queue, 604 * it is interrupted by a signal, or it times out waiting to be awakened. 605 */ 606int |
608sleepq_timedwait_sig(void *wchan) | 607sleepq_timedwait_sig(void *wchan, int pri) |
609{ 610 int rcatch, rvalt, rvals; 611 | 608{ 609 int rcatch, rvalt, rvals; 610 |
612 rcatch = sleepq_catch_signals(wchan); | 611 rcatch = sleepq_catch_signals(wchan, pri); |
613 rvalt = sleepq_check_timeout(); 614 rvals = sleepq_check_signals(); 615 thread_unlock(curthread); 616 if (rcatch) 617 return (rcatch); 618 if (rvals) 619 return (rvals); 620 return (rvalt); --- 47 unchanged lines hidden (view full) --- 668 * the sleeping flag if it isn't set though, so we just always 669 * do it. However, we can't assert that it is set. 670 */ 671 CTR3(KTR_PROC, "sleepq_wakeup: thread %p (pid %ld, %s)", 672 (void *)td, (long)td->td_proc->p_pid, td->td_name); 673 TD_CLR_SLEEPING(td); 674 675 /* Adjust priority if requested. */ | 612 rvalt = sleepq_check_timeout(); 613 rvals = sleepq_check_signals(); 614 thread_unlock(curthread); 615 if (rcatch) 616 return (rcatch); 617 if (rvals) 618 return (rvals); 619 return (rvalt); --- 47 unchanged lines hidden (view full) --- 667 * the sleeping flag if it isn't set though, so we just always 668 * do it. However, we can't assert that it is set. 669 */ 670 CTR3(KTR_PROC, "sleepq_wakeup: thread %p (pid %ld, %s)", 671 (void *)td, (long)td->td_proc->p_pid, td->td_name); 672 TD_CLR_SLEEPING(td); 673 674 /* Adjust priority if requested. */ |
676 MPASS(pri == -1 || (pri >= PRI_MIN && pri <= PRI_MAX)); 677 if (pri != -1 && td->td_priority > pri) | 675 MPASS(pri == 0 || (pri >= PRI_MIN && pri <= PRI_MAX)); 676 if (pri != 0 && td->td_priority > pri) |
678 sched_prio(td, pri); 679 setrunnable(td); 680} 681 682#ifdef INVARIANTS 683/* 684 * UMA zone item deallocator. 685 */ --- 69 unchanged lines hidden (view full) --- 755{ 756 struct sleepqueue *sq; 757 struct thread *td; 758 759 CTR2(KTR_PROC, "sleepq_broadcast(%p, %d)", wchan, flags); 760 KASSERT(wchan != NULL, ("%s: invalid NULL wait channel", __func__)); 761 MPASS((queue >= 0) && (queue < NR_SLEEPQS)); 762 sq = sleepq_lookup(wchan); | 677 sched_prio(td, pri); 678 setrunnable(td); 679} 680 681#ifdef INVARIANTS 682/* 683 * UMA zone item deallocator. 684 */ --- 69 unchanged lines hidden (view full) --- 754{ 755 struct sleepqueue *sq; 756 struct thread *td; 757 758 CTR2(KTR_PROC, "sleepq_broadcast(%p, %d)", wchan, flags); 759 KASSERT(wchan != NULL, ("%s: invalid NULL wait channel", __func__)); 760 MPASS((queue >= 0) && (queue < NR_SLEEPQS)); 761 sq = sleepq_lookup(wchan); |
763 if (sq == NULL) { 764 sleepq_release(wchan); | 762 if (sq == NULL) |
765 return; | 763 return; |
766 } | |
767 KASSERT(sq->sq_type == (flags & SLEEPQ_TYPE), 768 ("%s: mismatch between sleep/wakeup and cv_*", __func__)); 769 770 /* Resume all blocked threads on the sleep queue. */ 771 while (!TAILQ_EMPTY(&sq->sq_blocked[queue])) { 772 td = TAILQ_FIRST(&sq->sq_blocked[queue]); 773 thread_lock(td); 774 sleepq_resume_thread(sq, td, pri); 775 thread_unlock(td); 776 } | 764 KASSERT(sq->sq_type == (flags & SLEEPQ_TYPE), 765 ("%s: mismatch between sleep/wakeup and cv_*", __func__)); 766 767 /* Resume all blocked threads on the sleep queue. */ 768 while (!TAILQ_EMPTY(&sq->sq_blocked[queue])) { 769 td = TAILQ_FIRST(&sq->sq_blocked[queue]); 770 thread_lock(td); 771 sleepq_resume_thread(sq, td, pri); 772 thread_unlock(td); 773 } |
777 sleepq_release(wchan); | |
778} 779 780/* 781 * Time sleeping threads out. When the timeout expires, the thread is 782 * removed from the sleep queue and made runnable if it is still asleep. 783 */ 784static void 785sleepq_timeout(void *arg) --- 14 unchanged lines hidden (view full) --- 800 thread_lock(td); 801 if (TD_IS_SLEEPING(td) && TD_ON_SLEEPQ(td)) { 802 wchan = td->td_wchan; 803 sc = SC_LOOKUP(wchan); 804 THREAD_LOCKPTR_ASSERT(td, &sc->sc_lock); 805 sq = sleepq_lookup(wchan); 806 MPASS(sq != NULL); 807 td->td_flags |= TDF_TIMEOUT; | 774} 775 776/* 777 * Time sleeping threads out. When the timeout expires, the thread is 778 * removed from the sleep queue and made runnable if it is still asleep. 779 */ 780static void 781sleepq_timeout(void *arg) --- 14 unchanged lines hidden (view full) --- 796 thread_lock(td); 797 if (TD_IS_SLEEPING(td) && TD_ON_SLEEPQ(td)) { 798 wchan = td->td_wchan; 799 sc = SC_LOOKUP(wchan); 800 THREAD_LOCKPTR_ASSERT(td, &sc->sc_lock); 801 sq = sleepq_lookup(wchan); 802 MPASS(sq != NULL); 803 td->td_flags |= TDF_TIMEOUT; |
808 sleepq_resume_thread(sq, td, -1); | 804 sleepq_resume_thread(sq, td, 0); |
809 thread_unlock(td); 810 return; 811 } 812 813 /* 814 * If the thread is on the SLEEPQ but isn't sleeping yet, it 815 * can either be on another CPU in between sleepq_add() and 816 * one of the sleepq_*wait*() routines or it can be in --- 50 unchanged lines hidden (view full) --- 867 if (!TD_ON_SLEEPQ(td) || td->td_wchan != wchan) { 868 sleepq_release(wchan); 869 return; 870 } 871 /* Thread is asleep on sleep queue sq, so wake it up. */ 872 thread_lock(td); 873 MPASS(sq != NULL); 874 MPASS(td->td_wchan == wchan); | 805 thread_unlock(td); 806 return; 807 } 808 809 /* 810 * If the thread is on the SLEEPQ but isn't sleeping yet, it 811 * can either be on another CPU in between sleepq_add() and 812 * one of the sleepq_*wait*() routines or it can be in --- 50 unchanged lines hidden (view full) --- 863 if (!TD_ON_SLEEPQ(td) || td->td_wchan != wchan) { 864 sleepq_release(wchan); 865 return; 866 } 867 /* Thread is asleep on sleep queue sq, so wake it up. */ 868 thread_lock(td); 869 MPASS(sq != NULL); 870 MPASS(td->td_wchan == wchan); |
875 sleepq_resume_thread(sq, td, -1); | 871 sleepq_resume_thread(sq, td, 0); |
876 thread_unlock(td); 877 sleepq_release(wchan); 878} 879 880/* 881 * Abort a thread as if an interrupt had occurred. Only abort 882 * interruptible waits (unfortunately it isn't safe to abort others). 883 */ --- 27 unchanged lines hidden (view full) --- 911 if (!TD_IS_SLEEPING(td)) 912 return; 913 wchan = td->td_wchan; 914 MPASS(wchan != NULL); 915 sq = sleepq_lookup(wchan); 916 MPASS(sq != NULL); 917 918 /* Thread is asleep on sleep queue sq, so wake it up. */ | 872 thread_unlock(td); 873 sleepq_release(wchan); 874} 875 876/* 877 * Abort a thread as if an interrupt had occurred. Only abort 878 * interruptible waits (unfortunately it isn't safe to abort others). 879 */ --- 27 unchanged lines hidden (view full) --- 907 if (!TD_IS_SLEEPING(td)) 908 return; 909 wchan = td->td_wchan; 910 MPASS(wchan != NULL); 911 sq = sleepq_lookup(wchan); 912 MPASS(sq != NULL); 913 914 /* Thread is asleep on sleep queue sq, so wake it up. */ |
919 sleepq_resume_thread(sq, td, -1); | 915 sleepq_resume_thread(sq, td, 0); |
920} 921 922#ifdef DDB 923DB_SHOW_COMMAND(sleepq, db_show_sleepqueue) 924{ 925 struct sleepqueue_chain *sc; 926 struct sleepqueue *sq; 927#ifdef INVARIANTS --- 60 unchanged lines hidden --- | 916} 917 918#ifdef DDB 919DB_SHOW_COMMAND(sleepq, db_show_sleepqueue) 920{ 921 struct sleepqueue_chain *sc; 922 struct sleepqueue *sq; 923#ifdef INVARIANTS --- 60 unchanged lines hidden --- |