subr_sleepqueue.c (0269ae4c19ad779b43b0d6e2416ac7386945d692) subr_sleepqueue.c (f91aa773bea2bd0dff2d021c2d78fe78da78d52d)
1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2004 John Baldwin <jhb@FreeBSD.org>
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:

--- 109 unchanged lines hidden (view full) ---

118 * of the sleep queue API (e.g. sleep/wakeup and condition variables).
119 * The lock pointer is only used when invariants are enabled for various
120 * debugging checks.
121 *
122 * Locking key:
123 * c - sleep queue chain lock
124 */
125struct sleepqueue {
1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2004 John Baldwin <jhb@FreeBSD.org>
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:

--- 109 unchanged lines hidden (view full) ---

118 * of the sleep queue API (e.g. sleep/wakeup and condition variables).
119 * The lock pointer is only used when invariants are enabled for various
120 * debugging checks.
121 *
122 * Locking key:
123 * c - sleep queue chain lock
124 */
125struct sleepqueue {
126 TAILQ_HEAD(, thread) sq_blocked[NR_SLEEPQS]; /* (c) Blocked threads. */
126 struct threadqueue sq_blocked[NR_SLEEPQS]; /* (c) Blocked threads. */
127 u_int sq_blockedcnt[NR_SLEEPQS]; /* (c) N. of blocked threads. */
128 LIST_ENTRY(sleepqueue) sq_hash; /* (c) Chain and free list. */
129 LIST_HEAD(, sleepqueue) sq_free; /* (c) Free queues. */
130 void *sq_wchan; /* (c) Wait channel. */
131 int sq_type; /* (c) Queue type. */
132#ifdef INVARIANTS
133 struct lock_object *sq_lock; /* (c) Associated lock. */
134#endif

--- 749 unchanged lines hidden (view full) ---

884 TAILQ_INIT(&sq->sq_blocked[i]);
885 sq->sq_blockedcnt[i] = 0;
886 }
887 LIST_INIT(&sq->sq_free);
888 return (0);
889}
890
891/*
127 u_int sq_blockedcnt[NR_SLEEPQS]; /* (c) N. of blocked threads. */
128 LIST_ENTRY(sleepqueue) sq_hash; /* (c) Chain and free list. */
129 LIST_HEAD(, sleepqueue) sq_free; /* (c) Free queues. */
130 void *sq_wchan; /* (c) Wait channel. */
131 int sq_type; /* (c) Queue type. */
132#ifdef INVARIANTS
133 struct lock_object *sq_lock; /* (c) Associated lock. */
134#endif

--- 749 unchanged lines hidden (view full) ---

884 TAILQ_INIT(&sq->sq_blocked[i]);
885 sq->sq_blockedcnt[i] = 0;
886 }
887 LIST_INIT(&sq->sq_free);
888 return (0);
889}
890
891/*
892 * Find the highest priority thread sleeping on a wait channel and resume it.
892 * Find thread sleeping on a wait channel and resume it.
893 */
894int
895sleepq_signal(void *wchan, int flags, int pri, int queue)
896{
893 */
894int
895sleepq_signal(void *wchan, int flags, int pri, int queue)
896{
897 struct sleepqueue_chain *sc;
897 struct sleepqueue *sq;
898 struct sleepqueue *sq;
899 struct threadqueue *head;
898 struct thread *td, *besttd;
899 int wakeup_swapper;
900
901 CTR2(KTR_PROC, "sleepq_signal(%p, %d)", wchan, flags);
902 KASSERT(wchan != NULL, ("%s: invalid NULL wait channel", __func__));
903 MPASS((queue >= 0) && (queue < NR_SLEEPQS));
904 sq = sleepq_lookup(wchan);
905 if (sq == NULL)
906 return (0);
907 KASSERT(sq->sq_type == (flags & SLEEPQ_TYPE),
908 ("%s: mismatch between sleep/wakeup and cv_*", __func__));
909
900 struct thread *td, *besttd;
901 int wakeup_swapper;
902
903 CTR2(KTR_PROC, "sleepq_signal(%p, %d)", wchan, flags);
904 KASSERT(wchan != NULL, ("%s: invalid NULL wait channel", __func__));
905 MPASS((queue >= 0) && (queue < NR_SLEEPQS));
906 sq = sleepq_lookup(wchan);
907 if (sq == NULL)
908 return (0);
909 KASSERT(sq->sq_type == (flags & SLEEPQ_TYPE),
910 ("%s: mismatch between sleep/wakeup and cv_*", __func__));
911
910 /*
911 * Find the highest priority thread on the queue. If there is a
912 * tie, use the thread that first appears in the queue as it has
913 * been sleeping the longest since threads are always added to
914 * the tail of sleep queues.
915 */
916 besttd = TAILQ_FIRST(&sq->sq_blocked[queue]);
917 TAILQ_FOREACH(td, &sq->sq_blocked[queue], td_slpq) {
918 if (td->td_priority < besttd->td_priority)
912 head = &sq->sq_blocked[queue];
913 if (flags & SLEEPQ_UNFAIR) {
914 /*
915 * Find the most recently sleeping thread, but try to
916 * skip threads still in process of context switch to
917 * avoid spinning on the thread lock.
918 */
919 sc = SC_LOOKUP(wchan);
920 besttd = TAILQ_LAST_FAST(head, thread, td_slpq);
921 while (besttd->td_lock != &sc->sc_lock) {
922 td = TAILQ_PREV_FAST(besttd, head, thread, td_slpq);
923 if (td == NULL)
924 break;
919 besttd = td;
925 besttd = td;
926 }
927 } else {
928 /*
929 * Find the highest priority thread on the queue. If there
930 * is a tie, use the thread that first appears in the queue
931 * as it has been sleeping the longest since threads are
932 * always added to the tail of sleep queues.
933 */
934 besttd = td = TAILQ_FIRST(head);
935 while ((td = TAILQ_NEXT(td, td_slpq)) != NULL) {
936 if (td->td_priority < besttd->td_priority)
937 besttd = td;
938 }
920 }
921 MPASS(besttd != NULL);
922 thread_lock(besttd);
923 wakeup_swapper = sleepq_resume_thread(sq, besttd, pri);
924 thread_unlock(besttd);
925 return (wakeup_swapper);
926}
927

--- 539 unchanged lines hidden ---
939 }
940 MPASS(besttd != NULL);
941 thread_lock(besttd);
942 wakeup_swapper = sleepq_resume_thread(sq, besttd, pri);
943 thread_unlock(besttd);
944 return (wakeup_swapper);
945}
946

--- 539 unchanged lines hidden ---