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// sysclone_d tests basic functionalities of clone system call:
40//    - create a new thread
41//    - assign a new per-thread stack frame to the child thread
42//    - assign a new per-thread TLS to the child thread
43//
44// In addition to testing clone(), sysclone_d partially checks
45// functionalities of futex and exit system calls that are used to
46// facilitate thread exit and synchronization.
47//------------------------------------------------------------------------
48
49#include "riscv_test.h"
50#include "test_macros.h"
51#include "test_macros_mt_ecall.h"
52
53  RVTEST_RV64U
54  RVTEST_CODE_BEGIN
55
56#define MAX_NUM_THREADS 20
57
58//------------------------------------------------------------------------
59// Master thread creates new threads, waits for all threads to complete,
60// deallocates threads and checks result
61//------------------------------------------------------------------------
62  li      a0, MAX_NUM_THREADS
63  call    _create_threads
64
65  la      t6, n_worker_threads
66  ld      a0, (t6)
67  beqz    a0, _fail                   // exit if there's no worker thread
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// mt_test function executed by child threads
84//------------------------------------------------------------------------
85_mt_test:
86  // get this thread's TID
87  li      a7, SYSCALL_GETTID
88  ecall
89
90  // store the TID to both stack and TLS of this thread
91  addi    sp, sp, -8
92  sd      a0, (sp)
93  sd      a0, (tp)
94
95  RVTEST_CODE_END
96
97//------------------------------------------------------------------------
98// _check:
99//    The master thread looks into the stack and TLS of each child thread
100//    and check if the child thread's TID was written in both places.
101//
102//    This function assumes the following structure in the calling thread's
103//    stack frame
104//
105//    | child_stack_ptr_0       |  << fp: frame pointer
106//    | child_tls_ptr_0         |
107//    | child_thread_id_0       |
108//    | saved_child_thread_id_0 |
109//    | child_stack_ptr_1       |
110//    | child_tls_ptr_1         |
111//    | child_thread_id_1       |
112//    | saved_child_thread_id_1 |
113//    | ...                     |  << sp: stack pointer
114//
115//    This function takes a number of threads to check in a0
116//------------------------------------------------------------------------
117
118_check:
119  mv      t0, a0          // get the number of threads
120  mv      s0, ra          // save return register
121  mv      s1, sp          // save stack pointer
1221:
123  ld      t1, (sp)        // get child_thread_saved_id
124
125  addi    sp, sp, 8
126  ld      t2, (sp)        // get child_thread_id
127  bnez    t2, _fail       // this child_thread_id should have been cleared
128
129  addi    sp, sp, 8
130  ld      t3, (sp)        // get child_tls_ptr
131  ld      t3, (t3)        // get the first value stored in child's TLS
132  bne     t1, t3, _fail   // child_tid should have been saved in the TLS
133
134  addi    sp, sp, 8
135  ld      t4, (sp)        // get child_stack_ptr
136  li      t5, MEM_SIZE
137  add     t4, t4, t5      // get the high address of child's stack
138  ld      t4, -8(t4)      // get the first value stored in child's stack
139  bne     t1, t4, _fail   // child_tid should have been saved in the stack
140
141  addi    sp, sp, 8
142
143  // decrement the number of threads to wait for
144  addi    t0, t0, -1
145  bnez    t0, 1b
146
147  // finish checking all threads
148  mv      ra, s0                  // restore return register
149  mv      sp, s1                  // restore stack pointer
150  ret
151
152_fail:
153  li        a0, FAILURE
154  RVTEST_CODE_END
155
156  .data
157
158MT_DATA
159