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
36 */
37
38//------------------------------------------------------------------------
39// sysfutex_d tests basic functionalities of futex system call:
40//    - make a thread wait on a variable
41//    - wake up a thread waiting on a variable
42//------------------------------------------------------------------------
43
44#include "riscv_test.h"
45#include "test_macros.h"
46#include "test_macros_mt_ecall.h"
47
48  RVTEST_RV64U
49  RVTEST_CODE_BEGIN
50
51#define NUM_THREADS 1
52#define LOOP_COUNT  1000
53
54//------------------------------------------------------------------------
55// Master thread creates new threads, call _master function, waits for all
56// threads to complete, deallocates threads and checks result
57//------------------------------------------------------------------------
58  li      a0, NUM_THREADS
59  call    _create_threads
60
61  la      t6, n_worker_threads
62  ld      a0, (t6)
63  beqz    a0, _fail        // exit if there's no worker thread
64  call    _master_work
65
66  la      t6, n_worker_threads
67  ld      a0, (t6)
68  call    _join
69
70  la      t6, n_worker_threads
71  ld      a0, (t6)
72  call    _check
73
74  la      t6, n_worker_threads
75  ld      a0, (t6)
76  call    _delete_threads
77
78  li      a0, SUCCESS
79
80  RVTEST_CODE_END
81
82//------------------------------------------------------------------------
83// master_work function executed by the parent/master thread
84//
85//    Wake up thread(s) waiting on futex_X and then wait on futex_Y in a
86//    loop.
87//------------------------------------------------------------------------
88_master_work:
89  mv    s0, ra                  // save return address
90  li    t0, LOOP_COUNT
91  la    t1, count_master
92
931:
94  // futex(futex_X, FUTEX_WAKE_PRIVATE, 1)
95  la    a0, futex_X
96  li    a1, FUTEX_WAKE_PRIVATE
97  li    a2, 1                   // wake up at most 1 thread
98  li    a7, SYSCALL_FUTEX
99  ecall
100
101  // keep waking up until at least one thread is waken up
102  beqz  a0, 1b
103
104  // increment count_master
105  ld    t2, (t1)
106  addi  t2, t2, 1
107  sd    t2, (t1)
108
109  // futex(futex_Y, FUTEX_WAIT_PRIVATE, 0)
110  la    a0, futex_Y
111  li    a1, FUTEX_WAIT_PRIVATE
112  li    a2, 0                   // expected val of futex_Y
113  li    a7, SYSCALL_FUTEX
114  ecall
115
116  // decrement t0
117  addi  t0, t0, -1
118  bnez  t0, 1b
119
120  // restore return address and return
121  mv    ra, s0
122  ret
123
124//------------------------------------------------------------------------
125// mt_test function executed by child threads
126//
127//    Wait on futex_X and then wake up threads waiting on futex_Y in a loop
128//------------------------------------------------------------------------
129_mt_test:
130  li    t0, LOOP_COUNT
131  la    t1, count_child
132
1331:
134  // futex(futex_X, FUTEX_WAIT_PRIVATE, 1)
135  la    a0, futex_X
136  li    a1, FUTEX_WAIT_PRIVATE
137  li    a2, 0                   // expected val of futex_X
138  li    a7, SYSCALL_FUTEX
139  ecall
140
141  // increment count_child
142  ld    t2, (t1)
143  addi  t2, t2, 1
144  sd    t2, (t1)
145
1462:
147  // futex(futex_Y, FUTEX_WAKE_PRIVATE, 0)
148  la    a0, futex_Y
149  li    a1, FUTEX_WAKE_PRIVATE
150  li    a2, 1                   // wake up at most 1 thread
151  li    a7, SYSCALL_FUTEX
152  ecall
153
154  // keep waking up until at least one thread is waken up
155  beqz  a0, 2b
156
157  // decrement t0
158  addi  t0, t0, -1
159  bnez  t0, 1b
160
161  RVTEST_CODE_END
162
163//------------------------------------------------------------------------
164// _check:
165//    Each thread should do LOOP_COUNT iterations
166//------------------------------------------------------------------------
167
168_check:
169  la    t0, count_master
170  la    t1, count_child
171  li    t2, LOOP_COUNT
172
173  ld    t0, (t0)
174  bne   t0, t2, _fail
175
176  ld    t1, (t1)
177  bne   t1, t2, _fail
178
179  ret
180
181_fail:
182  li        a0, FAILURE
183  RVTEST_CODE_END
184
185  .data
186
187futex_X:  .dword  0
188futex_Y:  .dword  0
189
190count_master:   .dword  0
191count_child:    .dword  0
192
193MT_DATA
194