1/*
2 * Copyright (c) 2018, Cornell University
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or
6 * without modification, are permitted provided that the following
7 * conditions are met:
8 *
9 * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following
14 * disclaimer in the documentation and/or other materials provided
15 * with the distribution.
16 *
17 * Neither the name of Cornell University 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
22 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
23 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
26 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
29 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *
35 * Authors: Tuan Ta, Moyang Wang
36 */
37
38//------------------------------------------------------------------------
39// sysfutex3_d tests FUTEX_CMP_REQUEUE functionalities of futex system
40// call:
41//    - make worker threads waiting on futex 1
42//    - wake up 1 thread, requeue the rest of the threads to futex 2
43//    - wake all threads waiting on futex 1 and futex 2
44//------------------------------------------------------------------------
45
46#include "riscv_test.h"
47#include "test_macros.h"
48#include "test_macros_mt_ecall.h"
49
50  RVTEST_RV64U
51  RVTEST_CODE_BEGIN
52
53#define NUM_THREADS 20
54
55//------------------------------------------------------------------------
56// Master thread creates new threads, call _master function, waits for all
57// threads to complete, deallocates threads and checks result
58//------------------------------------------------------------------------
59  li      a0, NUM_THREADS
60  call    _create_threads
61
62  la      t6, n_worker_threads
63  ld      a0, (t6)
64  beqz    a0, _fail        // exit if there's no worker thread
65
66  call    _master_work
67
68  la      t6, n_worker_threads
69  ld      a0, (t6)
70  call    _join
71
72  la      t6, n_worker_threads
73  ld      a0, (t6)
74  call    _check
75
76  la      t6, n_worker_threads
77  ld      a0, (t6)
78  call    _delete_threads
79
80  li      a0, SUCCESS
81
82  RVTEST_CODE_END
83
84//------------------------------------------------------------------------
85// master_work function executed by the parent/master thread
86//------------------------------------------------------------------------
87_master_work:
88  mv    s0, ra                  // save return address
89  li    t0, 0                   // number of threads that have been waken
90  la    t1, n_worker_threads
91  ld    t1, (t1)
92
931:
94  // futex(futex_X, FUTEX_CMP_REQUEUE, 1, INT_MAX, futex_Y, *futex_X)
95  la    a0, futex_X
96  li    a1, FUTEX_CMP_REQUEUE
97  li    a2, 1                   // wake up at most 1 thread
98  li    a3, 1000                // practically is INT_MAX
99  la    a4, futex_Y             // move all other waiter to futex_Y
100  li    a5, 0
101  li    a7, SYSCALL_FUTEX
102  ecall
103
104  // loop until wake up one thread, all other waiter are requeued to
105  // futex_Y
106  beqz  a0, 1b
107
108  addi  t0, t0, 1
109
1102:
111  // alternating between futex_X and futex_Y
112  // because there could be new threads added to futex_X's queue
113  // after our futex_requeue
114
115  // futex(futex_Y, FUTEX_WAKE_PRIVATE, 0)
116  la    a0, futex_Y
117  li    a1, FUTEX_WAKE
118  li    a2, 1                   // wake up at most 1 thread
119  li    a7, SYSCALL_FUTEX
120  ecall
121
122  add   t0, t0, a0              // track the number of waken threads so far
123
124  // futex(futex_X, FUTEX_WAKE_PRIVATE, 0)
125  la    a0, futex_X
126  li    a1, FUTEX_WAKE
127  li    a2, 1                   // wake up at most 1 thread
128  li    a7, SYSCALL_FUTEX
129  ecall
130
131  add   t0, t0, a0              // track the number of waken threads so far
132
133  // keep waking up until all threads are waken up
134  blt   t0, t1, 2b
135
136  // restore return address and return
137  mv    ra, s0
138  ret
139
140//------------------------------------------------------------------------
141// mt_test function executed by child threads
142//
143//    Wait on futex_X
144//------------------------------------------------------------------------
145_mt_test:
146  // futex(futex_X, FUTEX_WAIT_PRIVATE, 1)
147  la    a0, futex_X
148  li    a1, FUTEX_WAIT
149  li    a2, 0                   // expected val of futex_X
150  li    a7, SYSCALL_FUTEX
151  ecall
152
153  RVTEST_CODE_END
154
155//------------------------------------------------------------------------
156// _check:
157//    counter should equals to number of child threads
158//------------------------------------------------------------------------
159
160_check:
161  ret
162
163_fail:
164  li        a0, FAILURE
165  RVTEST_CODE_END
166
167  .data
168
169futex_X:  .dword  0
170futex_Y:  .dword  0
171
172MT_DATA
173