Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0 2 : : /* 3 : : * <linux/swait.h> (simple wait queues ) implementation: 4 : : */ 5 : : #include "sched.h" 6 : : 7 : 3 : void __init_swait_queue_head(struct swait_queue_head *q, const char *name, 8 : : struct lock_class_key *key) 9 : : { 10 : 3 : raw_spin_lock_init(&q->lock); 11 : : lockdep_set_class_and_name(&q->lock, key, name); 12 : 3 : INIT_LIST_HEAD(&q->task_list); 13 : 3 : } 14 : : EXPORT_SYMBOL(__init_swait_queue_head); 15 : : 16 : : /* 17 : : * The thing about the wake_up_state() return value; I think we can ignore it. 18 : : * 19 : : * If for some reason it would return 0, that means the previously waiting 20 : : * task is already running, so it will observe condition true (or has already). 21 : : */ 22 : 3 : void swake_up_locked(struct swait_queue_head *q) 23 : : { 24 : : struct swait_queue *curr; 25 : : 26 : 3 : if (list_empty(&q->task_list)) 27 : 3 : return; 28 : : 29 : 3 : curr = list_first_entry(&q->task_list, typeof(*curr), task_list); 30 : 3 : wake_up_process(curr->task); 31 : 3 : list_del_init(&curr->task_list); 32 : : } 33 : : EXPORT_SYMBOL(swake_up_locked); 34 : : 35 : 3 : void swake_up_one(struct swait_queue_head *q) 36 : : { 37 : : unsigned long flags; 38 : : 39 : 3 : raw_spin_lock_irqsave(&q->lock, flags); 40 : 3 : swake_up_locked(q); 41 : 3 : raw_spin_unlock_irqrestore(&q->lock, flags); 42 : 3 : } 43 : : EXPORT_SYMBOL(swake_up_one); 44 : : 45 : : /* 46 : : * Does not allow usage from IRQ disabled, since we must be able to 47 : : * release IRQs to guarantee bounded hold time. 48 : : */ 49 : 0 : void swake_up_all(struct swait_queue_head *q) 50 : : { 51 : : struct swait_queue *curr; 52 : 0 : LIST_HEAD(tmp); 53 : : 54 : 0 : raw_spin_lock_irq(&q->lock); 55 : 0 : list_splice_init(&q->task_list, &tmp); 56 : 0 : while (!list_empty(&tmp)) { 57 : 0 : curr = list_first_entry(&tmp, typeof(*curr), task_list); 58 : : 59 : 0 : wake_up_state(curr->task, TASK_NORMAL); 60 : 0 : list_del_init(&curr->task_list); 61 : : 62 : 0 : if (list_empty(&tmp)) 63 : : break; 64 : : 65 : 0 : raw_spin_unlock_irq(&q->lock); 66 : 0 : raw_spin_lock_irq(&q->lock); 67 : : } 68 : 0 : raw_spin_unlock_irq(&q->lock); 69 : 0 : } 70 : : EXPORT_SYMBOL(swake_up_all); 71 : : 72 : : static void __prepare_to_swait(struct swait_queue_head *q, struct swait_queue *wait) 73 : : { 74 : 3 : wait->task = current; 75 : 3 : if (list_empty(&wait->task_list)) 76 : 3 : list_add_tail(&wait->task_list, &q->task_list); 77 : : } 78 : : 79 : 0 : void prepare_to_swait_exclusive(struct swait_queue_head *q, struct swait_queue *wait, int state) 80 : : { 81 : : unsigned long flags; 82 : : 83 : 0 : raw_spin_lock_irqsave(&q->lock, flags); 84 : : __prepare_to_swait(q, wait); 85 : 0 : set_current_state(state); 86 : 0 : raw_spin_unlock_irqrestore(&q->lock, flags); 87 : 0 : } 88 : : EXPORT_SYMBOL(prepare_to_swait_exclusive); 89 : : 90 : 3 : long prepare_to_swait_event(struct swait_queue_head *q, struct swait_queue *wait, int state) 91 : : { 92 : : unsigned long flags; 93 : : long ret = 0; 94 : : 95 : 3 : raw_spin_lock_irqsave(&q->lock, flags); 96 : 3 : if (signal_pending_state(state, current)) { 97 : : /* 98 : : * See prepare_to_wait_event(). TL;DR, subsequent swake_up_one() 99 : : * must not see us. 100 : : */ 101 : 0 : list_del_init(&wait->task_list); 102 : : ret = -ERESTARTSYS; 103 : : } else { 104 : : __prepare_to_swait(q, wait); 105 : 3 : set_current_state(state); 106 : : } 107 : 3 : raw_spin_unlock_irqrestore(&q->lock, flags); 108 : : 109 : 3 : return ret; 110 : : } 111 : : EXPORT_SYMBOL(prepare_to_swait_event); 112 : : 113 : 0 : void __finish_swait(struct swait_queue_head *q, struct swait_queue *wait) 114 : : { 115 : 0 : __set_current_state(TASK_RUNNING); 116 : 0 : if (!list_empty(&wait->task_list)) 117 : : list_del_init(&wait->task_list); 118 : 0 : } 119 : : 120 : 3 : void finish_swait(struct swait_queue_head *q, struct swait_queue *wait) 121 : : { 122 : : unsigned long flags; 123 : : 124 : 3 : __set_current_state(TASK_RUNNING); 125 : : 126 : 3 : if (!list_empty_careful(&wait->task_list)) { 127 : 3 : raw_spin_lock_irqsave(&q->lock, flags); 128 : : list_del_init(&wait->task_list); 129 : 3 : raw_spin_unlock_irqrestore(&q->lock, flags); 130 : : } 131 : 3 : } 132 : : EXPORT_SYMBOL(finish_swait);