1/* 2 * Copyright 2017, Data61 3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO) 4 * ABN 41 687 119 230. 5 * 6 * This software may be distributed and modified according to the terms of 7 * the BSD 2-Clause license. Note that NO WARRANTY is provided. 8 * See "LICENSE_BSD2.txt" for details. 9 * 10 * @TAG(DATA61_BSD) 11 */ 12 13#include <stdio.h> 14#include <sel4/sel4.h> 15#include <stdlib.h> 16#include <string.h> 17#include <vka/object.h> 18#include <sel4test/macros.h> 19 20#include "../helpers.h" 21 22/* declare some per thread variables for our tests. both bss and data */ 23static __thread seL4_Word bss_array[6] = {0}; 24static __thread seL4_Word data_array[6] = {1, 2, 3, 4, 5, 6}; 25 26static int test_root_tls(env_t env) 27{ 28 seL4_Word i; 29 for (i = 0; i < ARRAY_SIZE(bss_array); i++) { 30 test_eq(bss_array[i], (seL4_Word)0); 31 } 32 33 for (i = 0; i < ARRAY_SIZE(data_array); i++) { 34 test_eq(data_array[i], i + 1); 35 } 36 /* very the bss and data arrays containg the correct thing */ 37 return sel4test_get_result(); 38} 39DEFINE_TEST( 40 TLS0001, 41 "Test root thread accessing __thread variables", 42 test_root_tls, 43 true 44) 45 46static int 47tls_helper(seL4_Word helper, seL4_Word done_ep, seL4_Word start_ep, seL4_Word arg4) 48{ 49 seL4_Word i; 50 /* first verify all our initial data */ 51 for (i = 0; i < ARRAY_SIZE(bss_array); i++) { 52 test_eq(bss_array[i], (seL4_Word)0); 53 } 54 55 for (i = 0; i < ARRAY_SIZE(data_array); i++) { 56 test_eq(data_array[i], i + 1); 57 } 58 /* now update based on our thread */ 59 for (i = 0; i < ARRAY_SIZE(bss_array); i++) { 60 bss_array[i] = i + helper; 61 } 62 for (i = 0; i < ARRAY_SIZE(data_array); i++) { 63 data_array[i] = helper * ARRAY_SIZE(data_array) + i; 64 } 65 /* signal we are ready */ 66 seL4_Signal(done_ep); 67 /* wait for all threads are done and we are signaled to start */ 68 seL4_Wait(start_ep, NULL); 69 /* verify our arrays are still the same */ 70 for (i = 0; i < ARRAY_SIZE(bss_array); i++) { 71 test_eq(bss_array[i], i + helper); 72 } 73 for (i = 0; i < ARRAY_SIZE(data_array); i++) { 74 test_eq(data_array[i], helper * ARRAY_SIZE(data_array) + i); 75 } 76 return sel4test_get_result(); 77} 78 79static int test_threads_tls(env_t env) 80{ 81 /* create endpoints for synchronization */ 82 seL4_CPtr done_ep = vka_alloc_endpoint_leaky(&env->vka); 83 seL4_CPtr start_ep = vka_alloc_endpoint_leaky(&env->vka); 84 /* spawn some helper threads for manipulating the __thread variables */ 85 helper_thread_t helper_threads[4]; 86 int i; 87 for (i = 0; i < ARRAY_SIZE(helper_threads); i++) { 88 create_helper_thread(env, &helper_threads[i]); 89 start_helper(env, &helper_threads[i], tls_helper, i, done_ep, start_ep, 0); 90 } 91 /* wait for all threads to be done */ 92 for (i = 0; i < ARRAY_SIZE(helper_threads); i++) { 93 seL4_Wait(done_ep, NULL); 94 } 95 /* signal all threads to do the verification step */ 96 for (i = 0; i < ARRAY_SIZE(helper_threads); i++) { 97 seL4_Signal(start_ep); 98 } 99 /* wait for them all to complete */ 100 for (i = 0; i < ARRAY_SIZE(helper_threads); i++) { 101 wait_for_helper(&helper_threads[i]); 102 cleanup_helper(env, &helper_threads[i]); 103 } 104 return sel4test_get_result(); 105} 106DEFINE_TEST( 107 TLS0002, 108 "Test multiple threads using __thread variables", 109 test_threads_tls, 110 true 111) 112 113// Thread local storage value. 114#define INITIAL_TLS_VALUE 42 115#define TLS_INCREMENT_ITERATIONS 10000 116#define NUM_PARALLEL_THREADS 8 117 118static __thread int tls_value = INITIAL_TLS_VALUE; 119 120// Thread that competes. 121static int simple_tls_test_thread( 122 UNUSED seL4_Word arg1, 123 UNUSED seL4_Word arg2, 124 UNUSED seL4_Word arg3, 125 UNUSED seL4_Word arg4 126) 127{ 128 // Each thread should start with the same value. 129 if (tls_value != INITIAL_TLS_VALUE) { 130 sel4test_failure("TLS started with incorrect value"); 131 return -1; 132 } 133 134 // First try increment atomically. 135 int initial = tls_value; 136 int last = initial; 137 for (int i = 0; i < TLS_INCREMENT_ITERATIONS; i++) { 138 int next = __sync_add_and_fetch(&tls_value, 1); 139 if (next != last + 1) { 140 sel4test_failure("TLS did not increment atomically"); 141 return -1; 142 } 143 last = next; 144 } 145 146 if (tls_value != initial + TLS_INCREMENT_ITERATIONS) { 147 sel4test_failure("TLS did not increment atomically"); 148 return -1; 149 } 150 151 // Then try non-atomic. 152 // First try increment atomically. 153 initial = tls_value; 154 last = initial; 155 for (int i = 0; i < TLS_INCREMENT_ITERATIONS; i++) { 156 int next = ++tls_value; 157 if (next != last + 1) { 158 sel4test_failure("TLS did not increment correctly."); 159 return -1; 160 } 161 last = next; 162 } 163 164 if (tls_value != initial + TLS_INCREMENT_ITERATIONS) { 165 sel4test_failure("TLS did not increment correctly"); 166 return -1; 167 } 168 169 return 0; 170} 171 172int test_sel4utils_thread_tls(env_t env) 173{ 174 helper_thread_t threads[NUM_PARALLEL_THREADS]; 175 176 for (int t = 0; t < NUM_PARALLEL_THREADS; t++) { 177 create_helper_thread(env, &threads[t]); 178 start_helper( 179 env, &threads[t], 180 simple_tls_test_thread, 181 0, 0, 0, 0 182 ); 183 } 184 185 for (int t = 0; t < NUM_PARALLEL_THREADS; t++) { 186 wait_for_helper(&threads[t]); 187 cleanup_helper(env, &threads[t]); 188 } 189 190 return sel4test_get_result(); 191} 192DEFINE_TEST( 193 TLS0006, 194 "sel4utils_thread with distinct TLS should not interfere", 195 test_sel4utils_thread_tls, 196 true 197) 198