| 1 | import time |
| 2 | import sync |
| 3 | |
| 4 | struct St { |
| 5 | a int |
| 6 | } |
| 7 | |
| 8 | fn getint() int { |
| 9 | return 8 |
| 10 | } |
| 11 | |
| 12 | fn f1(ch1 chan int, ch2 chan St, ch3 chan int, ch4 chan int, ch5 chan int, mut sem sync.Semaphore) { |
| 13 | mut a := 5 |
| 14 | select { |
| 15 | a = <-ch3 { |
| 16 | a = 0 |
| 17 | } |
| 18 | b := <-ch2 { |
| 19 | a = b.a |
| 20 | } |
| 21 | ch3 <- 5 { |
| 22 | a = 1 |
| 23 | } |
| 24 | ch2 <- St{ |
| 25 | a: 37 |
| 26 | } { |
| 27 | a = 2 |
| 28 | } |
| 29 | ch4 <- (6 + 7 * 9) { |
| 30 | a = 8 |
| 31 | } |
| 32 | ch5 <- getint() { |
| 33 | a = 9 |
| 34 | } |
| 35 | 300 * time.millisecond { |
| 36 | a = 3 |
| 37 | } |
| 38 | } |
| 39 | assert a == 3 |
| 40 | sem.post() |
| 41 | } |
| 42 | |
| 43 | fn f2(ch1 chan St, ch2 chan int, mut sem sync.Semaphore) { |
| 44 | mut r := 23 |
| 45 | for i in 0 .. 2 { |
| 46 | select { |
| 47 | b := <-ch1 { |
| 48 | r = b.a |
| 49 | } |
| 50 | ch2 <- r { |
| 51 | r = 17 |
| 52 | } |
| 53 | } |
| 54 | if i == 0 { |
| 55 | assert r == 17 |
| 56 | } else { |
| 57 | assert r == 13 |
| 58 | } |
| 59 | } |
| 60 | sem.post() |
| 61 | } |
| 62 | |
| 63 | fn test_select_blocks() { |
| 64 | ch1 := chan int{cap: 1} |
| 65 | ch2 := chan St{} |
| 66 | ch3 := chan int{} |
| 67 | ch4 := chan int{} |
| 68 | ch5 := chan int{} |
| 69 | mut sem := sync.new_semaphore() |
| 70 | mut r := false |
| 71 | t := select { |
| 72 | b := <-ch1 { |
| 73 | println(b) |
| 74 | } |
| 75 | else { |
| 76 | // no channel ready |
| 77 | r = true |
| 78 | } |
| 79 | } |
| 80 | assert r == true |
| 81 | assert t == true |
| 82 | spawn f2(ch2, ch3, mut sem) |
| 83 | n := <-ch3 |
| 84 | assert n == 23 |
| 85 | ch2 <- St{ |
| 86 | a: 13 |
| 87 | } |
| 88 | sem.wait() |
| 89 | stopwatch := time.new_stopwatch() |
| 90 | spawn f1(ch1, ch2, ch3, ch4, ch5, mut sem) |
| 91 | sem.wait() |
| 92 | elapsed_ms := f64(stopwatch.elapsed()) / time.millisecond |
| 93 | // https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/high-resolution-timers |
| 94 | // > For example, for Windows running on an x86 processor, the default interval between |
| 95 | // > system clock ticks is typically about 15 milliseconds, and the minimum interval |
| 96 | // > between system clock ticks is about 1 millisecond. |
| 97 | assert elapsed_ms >= 280.0 // 300 - (15ms + 5ms just in case) |
| 98 | |
| 99 | ch1.close() |
| 100 | ch2.close() |
| 101 | mut h := 7 |
| 102 | mut is_open := true |
| 103 | if select { |
| 104 | _ := <-ch2 { |
| 105 | h = 0 |
| 106 | } |
| 107 | ch1 <- h { |
| 108 | h = 1 |
| 109 | } |
| 110 | else { |
| 111 | h = 2 |
| 112 | } |
| 113 | } { |
| 114 | panic('channel is still open') |
| 115 | } else { |
| 116 | is_open = false |
| 117 | } |
| 118 | // no branch should have run |
| 119 | assert h == 7 |
| 120 | // since all channels are closed `select` should return `false` |
| 121 | assert is_open == false |
| 122 | } |
| 123 | |
| 124 | fn test_select_closed_receive_beats_timeout() { |
| 125 | ch := chan bool{} |
| 126 | ch.close() |
| 127 | mut got := true |
| 128 | mut timed_out := false |
| 129 | select { |
| 130 | got = <-ch { |
| 131 | assert got == false |
| 132 | } |
| 133 | 10 * time.millisecond { |
| 134 | timed_out = true |
| 135 | } |
| 136 | } |
| 137 | assert got == false |
| 138 | assert timed_out == false |
| 139 | } |
| 140 | |
| 141 | fn test_select_else_skips_closed_buffered_receive() { |
| 142 | ch := chan int{cap: 1} |
| 143 | ch <- 1 |
| 144 | ch.close() |
| 145 | mut received := []int{} |
| 146 | mut did_else := false |
| 147 | select { |
| 148 | value := <-ch { |
| 149 | received << value |
| 150 | } |
| 151 | else { |
| 152 | did_else = true |
| 153 | } |
| 154 | } |
| 155 | assert did_else |
| 156 | assert received == [] |
| 157 | assert ch.len == 1 |
| 158 | assert <-ch == 1 |
| 159 | } |
| 160 | |
| 161 | fn test_select_expr_false_on_closed_buffered_receive() { |
| 162 | ch := chan int{cap: 1} |
| 163 | ch <- 1 |
| 164 | ch.close() |
| 165 | mut ran_branch := false |
| 166 | mut ran_else := false |
| 167 | if select { |
| 168 | _ := <-ch { |
| 169 | ran_branch = true |
| 170 | } |
| 171 | else { |
| 172 | ran_else = true |
| 173 | } |
| 174 | } { |
| 175 | assert false |
| 176 | } |
| 177 | assert ran_branch == false |
| 178 | assert ran_else == false |
| 179 | assert ch.len == 1 |
| 180 | assert <-ch == 1 |
| 181 | } |
| 182 | |