112771Sqtt2@cornell.edu/*
212771Sqtt2@cornell.edu * Copyright (c) 2018, Cornell University
312771Sqtt2@cornell.edu * All rights reserved.
412771Sqtt2@cornell.edu *
512771Sqtt2@cornell.edu * Redistribution and use in source and binary forms, with or
612771Sqtt2@cornell.edu * without modification, are permitted provided that the following
712771Sqtt2@cornell.edu * conditions are met:
812771Sqtt2@cornell.edu *
912771Sqtt2@cornell.edu * Redistributions of source code must retain the above copyright
1012771Sqtt2@cornell.edu * notice, this list of conditions and the following disclaimer.
1112771Sqtt2@cornell.edu *
1212771Sqtt2@cornell.edu * Redistributions in binary form must reproduce the above
1312771Sqtt2@cornell.edu * copyright notice, this list of conditions and the following
1412771Sqtt2@cornell.edu * disclaimer in the documentation and/or other materials provided
1512771Sqtt2@cornell.edu * with the distribution.
1612771Sqtt2@cornell.edu *
1712771Sqtt2@cornell.edu * Neither the name of Cornell University nor the names of its
1812771Sqtt2@cornell.edu * contributors may be used to endorse or promote products derived
1912771Sqtt2@cornell.edu * from this software without specific prior written permission.
2012771Sqtt2@cornell.edu *
2112771Sqtt2@cornell.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
2212771Sqtt2@cornell.edu * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
2312771Sqtt2@cornell.edu * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
2412771Sqtt2@cornell.edu * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2512771Sqtt2@cornell.edu * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
2612771Sqtt2@cornell.edu * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2712771Sqtt2@cornell.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2812771Sqtt2@cornell.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
2912771Sqtt2@cornell.edu * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
3012771Sqtt2@cornell.edu * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3112771Sqtt2@cornell.edu * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
3212771Sqtt2@cornell.edu * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3312771Sqtt2@cornell.edu * POSSIBILITY OF SUCH DAMAGE.
3412771Sqtt2@cornell.edu *
3512771Sqtt2@cornell.edu * Authors: Tuan Ta, Moyang
3612771Sqtt2@cornell.edu */
3712771Sqtt2@cornell.edu
3812771Sqtt2@cornell.edu//------------------------------------------------------------------------
3912771Sqtt2@cornell.edu// sysfutex_d tests FUTEX_WAKE_OP functionalities of futex system call:
4012771Sqtt2@cornell.edu//    - make a thread wait on a variable
4112771Sqtt2@cornell.edu//    - atomically wake up a thread waiting on a variable and perform
4212771Sqtt2@cornell.edu//      a operation on a value
4312771Sqtt2@cornell.edu//------------------------------------------------------------------------
4412771Sqtt2@cornell.edu
4512771Sqtt2@cornell.edu#include "riscv_test.h"
4612771Sqtt2@cornell.edu#include "test_macros.h"
4712771Sqtt2@cornell.edu#include "test_macros_mt_ecall.h"
4812771Sqtt2@cornell.edu
4912771Sqtt2@cornell.edu  RVTEST_RV64U
5012771Sqtt2@cornell.edu  RVTEST_CODE_BEGIN
5112771Sqtt2@cornell.edu
5212771Sqtt2@cornell.edu#define NUM_THREADS 1
5312771Sqtt2@cornell.edu#define LOOP_COUNT  1000
5412771Sqtt2@cornell.edu
5512771Sqtt2@cornell.edu//------------------------------------------------------------------------
5612771Sqtt2@cornell.edu// Master thread creates new threads, call _master function, waits for all
5712771Sqtt2@cornell.edu// threads to complete, deallocates threads and checks result
5812771Sqtt2@cornell.edu//------------------------------------------------------------------------
5912771Sqtt2@cornell.edu  li      a0, NUM_THREADS
6012771Sqtt2@cornell.edu  call    _create_threads
6112771Sqtt2@cornell.edu
6212771Sqtt2@cornell.edu  la      t6, n_worker_threads
6312771Sqtt2@cornell.edu  ld      a0, (t6)
6412771Sqtt2@cornell.edu  beqz    a0, _fail        // exit if there's no worker thread
6512771Sqtt2@cornell.edu
6612771Sqtt2@cornell.edu  call    _master_work
6712771Sqtt2@cornell.edu
6812771Sqtt2@cornell.edu  la      t6, n_worker_threads
6912771Sqtt2@cornell.edu  ld      a0, (t6)
7012771Sqtt2@cornell.edu  call    _join
7112771Sqtt2@cornell.edu
7212771Sqtt2@cornell.edu  la      t6, n_worker_threads
7312771Sqtt2@cornell.edu  ld      a0, (t6)
7412771Sqtt2@cornell.edu  call    _check
7512771Sqtt2@cornell.edu
7612771Sqtt2@cornell.edu  la      t6, n_worker_threads
7712771Sqtt2@cornell.edu  ld      a0, (t6)
7812771Sqtt2@cornell.edu  call    _delete_threads
7912771Sqtt2@cornell.edu
8012771Sqtt2@cornell.edu  li      a0, SUCCESS
8112771Sqtt2@cornell.edu
8212771Sqtt2@cornell.edu  RVTEST_CODE_END
8312771Sqtt2@cornell.edu
8412771Sqtt2@cornell.edu//------------------------------------------------------------------------
8512771Sqtt2@cornell.edu// master_work function executed by the parent/master thread
8612771Sqtt2@cornell.edu//
8712771Sqtt2@cornell.edu//    Wake up thread(s) waiting on futex_X and then wait on futex_Y in a
8812771Sqtt2@cornell.edu//    loop. Also atomically modify futex_Z during the wake-up.
8912771Sqtt2@cornell.edu//------------------------------------------------------------------------
9012771Sqtt2@cornell.edu_master_work:
9112771Sqtt2@cornell.edu  mv    s0, ra                  // save return address
9212771Sqtt2@cornell.edu  li    t0, LOOP_COUNT
9312771Sqtt2@cornell.edu  la    t1, count_master
9412771Sqtt2@cornell.edu  la    t3, count_Z
9512771Sqtt2@cornell.edu
9612771Sqtt2@cornell.edu1:
9712771Sqtt2@cornell.edu  // futex(futex_X, FUTEX_WAKE_OP, 1, val2, futex_Z, val3 )
9812771Sqtt2@cornell.edu  la    a0, futex_X
9912771Sqtt2@cornell.edu  li    a1, FUTEX_WAKE_OP
10012771Sqtt2@cornell.edu  li    a2, 1                   // wake up at most 1 thread
10112771Sqtt2@cornell.edu  li    a3, 0                   // should not perform the second wake up
10212771Sqtt2@cornell.edu  la    a4, futex_Z             // add 1 to futex_Z each time
10312771Sqtt2@cornell.edu  li    a5, FUTEX_OP(FUTEX_OP_ADD, 1, FUTEX_OP_CMP_LT, 0)
10412771Sqtt2@cornell.edu  li    a7, SYSCALL_FUTEX
10512771Sqtt2@cornell.edu  ecall
10612771Sqtt2@cornell.edu
10712771Sqtt2@cornell.edu  // increment count_Z (should equals to futex_Z)
10812771Sqtt2@cornell.edu  ld    t4, (t3)
10912771Sqtt2@cornell.edu  addi  t4, t4, 1
11012771Sqtt2@cornell.edu  sd    t4, (t3)
11112771Sqtt2@cornell.edu
11212771Sqtt2@cornell.edu  // keep waking up until at least one thread is waken up
11312771Sqtt2@cornell.edu  beqz  a0, 1b
11412771Sqtt2@cornell.edu
11512771Sqtt2@cornell.edu  // increment count_master
11612771Sqtt2@cornell.edu  ld    t2, (t1)
11712771Sqtt2@cornell.edu  addi  t2, t2, 1
11812771Sqtt2@cornell.edu  sd    t2, (t1)
11912771Sqtt2@cornell.edu
12012771Sqtt2@cornell.edu  // futex(futex_Y, FUTEX_WAIT_PRIVATE, 0)
12112771Sqtt2@cornell.edu  la    a0, futex_Y
12212771Sqtt2@cornell.edu  li    a1, FUTEX_WAIT_PRIVATE
12312771Sqtt2@cornell.edu  li    a2, 0                   // expected val of futex_Y
12412771Sqtt2@cornell.edu  li    a7, SYSCALL_FUTEX
12512771Sqtt2@cornell.edu  ecall
12612771Sqtt2@cornell.edu
12712771Sqtt2@cornell.edu  // decrement t0
12812771Sqtt2@cornell.edu  addi  t0, t0, -1
12912771Sqtt2@cornell.edu  bnez  t0, 1b
13012771Sqtt2@cornell.edu
13112771Sqtt2@cornell.edu  // restore return address and return
13212771Sqtt2@cornell.edu  mv    ra, s0
13312771Sqtt2@cornell.edu  ret
13412771Sqtt2@cornell.edu
13512771Sqtt2@cornell.edu//------------------------------------------------------------------------
13612771Sqtt2@cornell.edu// mt_test function executed by child threads
13712771Sqtt2@cornell.edu//
13812771Sqtt2@cornell.edu//    Wait on futex_X and then wake up threads waiting on futex_Y in a loop
13912771Sqtt2@cornell.edu//------------------------------------------------------------------------
14012771Sqtt2@cornell.edu_mt_test:
14112771Sqtt2@cornell.edu  li    t0, LOOP_COUNT
14212771Sqtt2@cornell.edu  la    t1, count_child
14312771Sqtt2@cornell.edu
14412771Sqtt2@cornell.edu1:
14512771Sqtt2@cornell.edu  // futex(futex_X, FUTEX_WAIT_PRIVATE, 1)
14612771Sqtt2@cornell.edu  la    a0, futex_X
14712771Sqtt2@cornell.edu  li    a1, FUTEX_WAIT_PRIVATE
14812771Sqtt2@cornell.edu  li    a2, 0                   // expected val of futex_X
14912771Sqtt2@cornell.edu  li    a7, SYSCALL_FUTEX
15012771Sqtt2@cornell.edu  ecall
15112771Sqtt2@cornell.edu
15212771Sqtt2@cornell.edu  // increment count_child
15312771Sqtt2@cornell.edu  ld    t2, (t1)
15412771Sqtt2@cornell.edu  addi  t2, t2, 1
15512771Sqtt2@cornell.edu  sd    t2, (t1)
15612771Sqtt2@cornell.edu
15712771Sqtt2@cornell.edu2:
15812771Sqtt2@cornell.edu  // futex(futex_Y, FUTEX_WAKE_PRIVATE, 0)
15912771Sqtt2@cornell.edu  la    a0, futex_Y
16012771Sqtt2@cornell.edu  li    a1, FUTEX_WAKE_PRIVATE
16112771Sqtt2@cornell.edu  li    a2, 1                   // wake up at most 1 thread
16212771Sqtt2@cornell.edu  li    a7, SYSCALL_FUTEX
16312771Sqtt2@cornell.edu  ecall
16412771Sqtt2@cornell.edu
16512771Sqtt2@cornell.edu  // keep waking up until at least one thread is waken up
16612771Sqtt2@cornell.edu  beqz  a0, 2b
16712771Sqtt2@cornell.edu
16812771Sqtt2@cornell.edu  // decrement t0
16912771Sqtt2@cornell.edu  addi  t0, t0, -1
17012771Sqtt2@cornell.edu  bnez  t0, 1b
17112771Sqtt2@cornell.edu
17212771Sqtt2@cornell.edu  RVTEST_CODE_END
17312771Sqtt2@cornell.edu
17412771Sqtt2@cornell.edu//------------------------------------------------------------------------
17512771Sqtt2@cornell.edu// _check:
17612771Sqtt2@cornell.edu//    Each thread should do LOOP_COUNT iterations
17712771Sqtt2@cornell.edu//------------------------------------------------------------------------
17812771Sqtt2@cornell.edu
17912771Sqtt2@cornell.edu_check:
18012771Sqtt2@cornell.edu  la    t0, count_master
18112771Sqtt2@cornell.edu  la    t1, count_child
18212771Sqtt2@cornell.edu  li    t2, LOOP_COUNT
18312771Sqtt2@cornell.edu  la    t3, count_Z
18412771Sqtt2@cornell.edu  la    t4, futex_Z
18512771Sqtt2@cornell.edu
18612771Sqtt2@cornell.edu  ld    t0, (t0)
18712771Sqtt2@cornell.edu  bne   t0, t2, _fail
18812771Sqtt2@cornell.edu
18912771Sqtt2@cornell.edu  ld    t1, (t1)
19012771Sqtt2@cornell.edu  bne   t1, t2, _fail
19112771Sqtt2@cornell.edu
19212771Sqtt2@cornell.edu  ld    t3, (t3)
19312771Sqtt2@cornell.edu  ld    t4, (t4)
19412771Sqtt2@cornell.edu  bne   t3, t4, _fail
19512771Sqtt2@cornell.edu
19612771Sqtt2@cornell.edu  ret
19712771Sqtt2@cornell.edu
19812771Sqtt2@cornell.edu_fail:
19912771Sqtt2@cornell.edu  li        a0, FAILURE
20012771Sqtt2@cornell.edu  RVTEST_CODE_END
20112771Sqtt2@cornell.edu
20212771Sqtt2@cornell.edu  .data
20312771Sqtt2@cornell.edu
20412771Sqtt2@cornell.edufutex_X:  .dword  0
20512771Sqtt2@cornell.edufutex_Y:  .dword  0
20612771Sqtt2@cornell.edufutex_Z:  .dword  0
20712771Sqtt2@cornell.edu
20812771Sqtt2@cornell.educount_master:   .dword  0
20912771Sqtt2@cornell.educount_child:    .dword  0
21012771Sqtt2@cornell.educount_Z:        .dword  0
21112771Sqtt2@cornell.edu
21212771Sqtt2@cornell.eduMT_DATA
213