blob: 525da19bf2de5243a5e978162afed0ce6efbb5a5 [file] [log] [blame] [edit]
/*
* Copyright 2017, Data61, CSIRO (ABN 41 687 119 230)
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <stdio.h>
#include <sel4/sel4.h>
#include <stdlib.h>
#include <string.h>
#include <vka/object.h>
#include <sel4test/macros.h>
#include "../helpers.h"
/* declare some per thread variables for our tests. both bss and data */
static __thread seL4_Word bss_array[6] = {0};
static __thread seL4_Word data_array[6] = {1, 2, 3, 4, 5, 6};
static int test_root_tls(env_t env)
{
seL4_Word i;
for (i = 0; i < ARRAY_SIZE(bss_array); i++) {
test_eq(bss_array[i], (seL4_Word)0);
}
for (i = 0; i < ARRAY_SIZE(data_array); i++) {
test_eq(data_array[i], i + 1);
}
/* very the bss and data arrays containg the correct thing */
return sel4test_get_result();
}
DEFINE_TEST(
TLS0001,
"Test root thread accessing __thread variables",
test_root_tls,
true
)
static int
tls_helper(seL4_Word helper, seL4_Word done_ep, seL4_Word start_ep, seL4_Word arg4)
{
seL4_Word i;
/* first verify all our initial data */
for (i = 0; i < ARRAY_SIZE(bss_array); i++) {
test_eq(bss_array[i], (seL4_Word)0);
}
for (i = 0; i < ARRAY_SIZE(data_array); i++) {
test_eq(data_array[i], i + 1);
}
/* now update based on our thread */
for (i = 0; i < ARRAY_SIZE(bss_array); i++) {
bss_array[i] = i + helper;
}
for (i = 0; i < ARRAY_SIZE(data_array); i++) {
data_array[i] = helper * ARRAY_SIZE(data_array) + i;
}
/* signal we are ready */
seL4_Signal(done_ep);
/* wait for all threads are done and we are signaled to start */
seL4_Wait(start_ep, NULL);
/* verify our arrays are still the same */
for (i = 0; i < ARRAY_SIZE(bss_array); i++) {
test_eq(bss_array[i], i + helper);
}
for (i = 0; i < ARRAY_SIZE(data_array); i++) {
test_eq(data_array[i], helper * ARRAY_SIZE(data_array) + i);
}
return sel4test_get_result();
}
static int test_threads_tls(env_t env)
{
/* create endpoints for synchronization */
seL4_CPtr done_ep = vka_alloc_endpoint_leaky(&env->vka);
seL4_CPtr start_ep = vka_alloc_endpoint_leaky(&env->vka);
/* spawn some helper threads for manipulating the __thread variables */
helper_thread_t helper_threads[4];
int i;
for (i = 0; i < ARRAY_SIZE(helper_threads); i++) {
create_helper_thread(env, &helper_threads[i]);
start_helper(env, &helper_threads[i], tls_helper, i, done_ep, start_ep, 0);
}
/* wait for all threads to be done */
for (i = 0; i < ARRAY_SIZE(helper_threads); i++) {
seL4_Wait(done_ep, NULL);
}
/* signal all threads to do the verification step */
for (i = 0; i < ARRAY_SIZE(helper_threads); i++) {
seL4_Signal(start_ep);
}
/* wait for them all to complete */
for (i = 0; i < ARRAY_SIZE(helper_threads); i++) {
wait_for_helper(&helper_threads[i]);
cleanup_helper(env, &helper_threads[i]);
}
return sel4test_get_result();
}
DEFINE_TEST(
TLS0002,
"Test multiple threads using __thread variables",
test_threads_tls,
true
)
// Thread local storage value.
#define INITIAL_TLS_VALUE 42
#define TLS_INCREMENT_ITERATIONS 10000
#define NUM_PARALLEL_THREADS 8
static __thread int tls_value = INITIAL_TLS_VALUE;
// Thread that competes.
static int simple_tls_test_thread(
UNUSED seL4_Word arg1,
UNUSED seL4_Word arg2,
UNUSED seL4_Word arg3,
UNUSED seL4_Word arg4
)
{
// Each thread should start with the same value.
if (tls_value != INITIAL_TLS_VALUE) {
sel4test_failure("TLS started with incorrect value");
return -1;
}
// First try increment atomically.
int initial = tls_value;
int last = initial;
for (int i = 0; i < TLS_INCREMENT_ITERATIONS; i++) {
int next = __sync_add_and_fetch(&tls_value, 1);
if (next != last + 1) {
sel4test_failure("TLS did not increment atomically");
return -1;
}
last = next;
}
if (tls_value != initial + TLS_INCREMENT_ITERATIONS) {
sel4test_failure("TLS did not increment atomically");
return -1;
}
// Then try non-atomic.
// First try increment atomically.
initial = tls_value;
last = initial;
for (int i = 0; i < TLS_INCREMENT_ITERATIONS; i++) {
int next = ++tls_value;
if (next != last + 1) {
sel4test_failure("TLS did not increment correctly.");
return -1;
}
last = next;
}
if (tls_value != initial + TLS_INCREMENT_ITERATIONS) {
sel4test_failure("TLS did not increment correctly");
return -1;
}
return 0;
}
int test_sel4utils_thread_tls(env_t env)
{
helper_thread_t threads[NUM_PARALLEL_THREADS];
for (int t = 0; t < NUM_PARALLEL_THREADS; t++) {
create_helper_thread(env, &threads[t]);
start_helper(
env, &threads[t],
simple_tls_test_thread,
0, 0, 0, 0
);
}
for (int t = 0; t < NUM_PARALLEL_THREADS; t++) {
wait_for_helper(&threads[t]);
cleanup_helper(env, &threads[t]);
}
return sel4test_get_result();
}
DEFINE_TEST(
TLS0006,
"sel4utils_thread with distinct TLS should not interfere",
test_sel4utils_thread_tls,
true
)