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 36 */ 37 38//------------------------------------------------------------------------ 39// sysfutex_d tests FUTEX_WAKE_OP functionalities of futex system call: 40// - make a thread wait on a variable 41// - atomically wake up a thread waiting on a variable and perform 42// a operation on a value 43//------------------------------------------------------------------------ 44 45#include "riscv_test.h" 46#include "test_macros.h" 47#include "test_macros_mt_ecall.h" 48 49 RVTEST_RV64U 50 RVTEST_CODE_BEGIN 51 52#define NUM_THREADS 1 53#define LOOP_COUNT 1000 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// Wake up thread(s) waiting on futex_X and then wait on futex_Y in a 88// loop. Also atomically modify futex_Z during the wake-up. 89//------------------------------------------------------------------------ 90_master_work: 91 mv s0, ra // save return address 92 li t0, LOOP_COUNT 93 la t1, count_master 94 la t3, count_Z 95 961: 97 // futex(futex_X, FUTEX_WAKE_OP, 1, val2, futex_Z, val3 ) 98 la a0, futex_X 99 li a1, FUTEX_WAKE_OP 100 li a2, 1 // wake up at most 1 thread 101 li a3, 0 // should not perform the second wake up 102 la a4, futex_Z // add 1 to futex_Z each time 103 li a5, FUTEX_OP(FUTEX_OP_ADD, 1, FUTEX_OP_CMP_LT, 0) 104 li a7, SYSCALL_FUTEX 105 ecall 106 107 // increment count_Z (should equals to futex_Z) 108 ld t4, (t3) 109 addi t4, t4, 1 110 sd t4, (t3) 111 112 // keep waking up until at least one thread is waken up 113 beqz a0, 1b 114 115 // increment count_master 116 ld t2, (t1) 117 addi t2, t2, 1 118 sd t2, (t1) 119 120 // futex(futex_Y, FUTEX_WAIT_PRIVATE, 0) 121 la a0, futex_Y 122 li a1, FUTEX_WAIT_PRIVATE 123 li a2, 0 // expected val of futex_Y 124 li a7, SYSCALL_FUTEX 125 ecall 126 127 // decrement t0 128 addi t0, t0, -1 129 bnez t0, 1b 130 131 // restore return address and return 132 mv ra, s0 133 ret 134 135//------------------------------------------------------------------------ 136// mt_test function executed by child threads 137// 138// Wait on futex_X and then wake up threads waiting on futex_Y in a loop 139//------------------------------------------------------------------------ 140_mt_test: 141 li t0, LOOP_COUNT 142 la t1, count_child 143 1441: 145 // futex(futex_X, FUTEX_WAIT_PRIVATE, 1) 146 la a0, futex_X 147 li a1, FUTEX_WAIT_PRIVATE 148 li a2, 0 // expected val of futex_X 149 li a7, SYSCALL_FUTEX 150 ecall 151 152 // increment count_child 153 ld t2, (t1) 154 addi t2, t2, 1 155 sd t2, (t1) 156 1572: 158 // futex(futex_Y, FUTEX_WAKE_PRIVATE, 0) 159 la a0, futex_Y 160 li a1, FUTEX_WAKE_PRIVATE 161 li a2, 1 // wake up at most 1 thread 162 li a7, SYSCALL_FUTEX 163 ecall 164 165 // keep waking up until at least one thread is waken up 166 beqz a0, 2b 167 168 // decrement t0 169 addi t0, t0, -1 170 bnez t0, 1b 171 172 RVTEST_CODE_END 173 174//------------------------------------------------------------------------ 175// _check: 176// Each thread should do LOOP_COUNT iterations 177//------------------------------------------------------------------------ 178 179_check: 180 la t0, count_master 181 la t1, count_child 182 li t2, LOOP_COUNT 183 la t3, count_Z 184 la t4, futex_Z 185 186 ld t0, (t0) 187 bne t0, t2, _fail 188 189 ld t1, (t1) 190 bne t1, t2, _fail 191 192 ld t3, (t3) 193 ld t4, (t4) 194 bne t3, t4, _fail 195 196 ret 197 198_fail: 199 li a0, FAILURE 200 RVTEST_CODE_END 201 202 .data 203 204futex_X: .dword 0 205futex_Y: .dword 0 206futex_Z: .dword 0 207 208count_master: .dword 0 209count_child: .dword 0 210count_Z: .dword 0 211 212MT_DATA 213