You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
288 lines
7.8 KiB
288 lines
7.8 KiB
/* |
|
* Copyright (C) 2013 Christian Mehlis <mehlis@inf.fu-berlin.de> |
|
* Copyright (C) 2013 René Kijewski <rene.kijewski@fu-berlin.de> |
|
* Copyright (C) 2015 Martine Lenders <mlenders@inf.fu-berlin.de> |
|
* |
|
* This file is subject to the terms and conditions of the GNU Lesser |
|
* General Public License v2.1. See the file LICENSE in the top level |
|
* directory for more details. |
|
*/ |
|
|
|
/** |
|
* @ingroup tests |
|
* @{ |
|
* |
|
* @file |
|
* @brief Semaphore test application |
|
* |
|
* @author Christian Mehlis <mehlis@inf.fu-berlin.de> |
|
* @author René Kijewski <rene.kijewski@fu-berlin.de> |
|
* @author Martine Lenders <mlenders@inf.fu-berlin.de> |
|
* |
|
* @} |
|
*/ |
|
|
|
#include <errno.h> |
|
#include <stdio.h> |
|
#include <semaphore.h> |
|
|
|
#include "fmt.h" |
|
#include "msg.h" |
|
#include "timex.h" |
|
#include "thread.h" |
|
#include "xtimer.h" |
|
|
|
#define SEMAPHORE_MSG_QUEUE_SIZE (8) |
|
#define SEMAPHORE_TEST_THREADS (5) |
|
static char test1_thread_stack[THREAD_STACKSIZE_MAIN]; |
|
static char test2_thread_stack[SEMAPHORE_TEST_THREADS][THREAD_STACKSIZE_MAIN]; |
|
static msg_t main_msg_queue[SEMAPHORE_MSG_QUEUE_SIZE]; |
|
static msg_t test1_msg_queue[SEMAPHORE_MSG_QUEUE_SIZE]; |
|
|
|
static sem_t s1; |
|
static sem_t s2; |
|
|
|
static void *test1_second_thread(void *arg) |
|
{ |
|
(void) arg; |
|
msg_init_queue(test1_msg_queue, SEMAPHORE_MSG_QUEUE_SIZE); |
|
puts("second: sem_trywait"); |
|
|
|
if (sem_trywait(&s1) < 0) { |
|
puts("second: sem_trywait failed"); |
|
} |
|
|
|
puts("second: sem_trywait done with == 0"); |
|
|
|
puts("second: wait for post"); |
|
|
|
if (sem_wait(&s1) < 0) { |
|
puts("second: sem_wait failed"); |
|
} |
|
|
|
puts("second: sem was posted"); |
|
|
|
puts("second: end"); |
|
return NULL; |
|
} |
|
|
|
static void test1(void) |
|
{ |
|
puts("first: sem_init"); |
|
|
|
if (sem_init(&s1, 0, 0) < 0) { |
|
puts("first: sem_init failed"); |
|
} |
|
|
|
puts("first: thread create"); |
|
kernel_pid_t pid = thread_create(test1_thread_stack, |
|
sizeof(test1_thread_stack), |
|
THREAD_PRIORITY_MAIN - 1, |
|
THREAD_CREATE_STACKTEST | |
|
THREAD_CREATE_WOUT_YIELD, |
|
test1_second_thread, |
|
NULL, |
|
"second"); |
|
if (pid == KERNEL_PID_UNDEF) { |
|
puts("first: thread create failed"); |
|
} |
|
puts("first: thread created"); |
|
|
|
puts("first: sem_getvalue"); |
|
int val; |
|
|
|
if (sem_getvalue(&s1, &val) < 0 || val != 0) { |
|
puts("first: sem_getvalue FAILED"); |
|
} |
|
|
|
puts("first: sem_getvalue != 0"); |
|
|
|
puts("first: do yield"); |
|
thread_yield(); |
|
puts("first: done yield"); |
|
|
|
/*****************************************************************************/ |
|
|
|
puts("first: sem_trywait"); |
|
|
|
if (sem_trywait(&s1) < 0) { |
|
puts("first: sem_trywait FAILED"); |
|
} |
|
|
|
puts("first: sem_trywait done"); |
|
|
|
puts("first: sem_post"); |
|
|
|
if (sem_post(&s1) < 0) { |
|
puts("first: sem_post FAILED"); |
|
} |
|
|
|
puts("first: sem_post done"); |
|
|
|
/*****************************************************************************/ |
|
|
|
puts("first: sem_destroy"); |
|
|
|
if (sem_destroy(&s1) < 0) { |
|
puts("first: sem_destroy FAILED"); |
|
} |
|
|
|
puts("first: end"); |
|
} |
|
|
|
static void *priority_sema_thread(void *name) |
|
{ |
|
msg_t msg_queue[SEMAPHORE_MSG_QUEUE_SIZE]; |
|
msg_init_queue(msg_queue, SEMAPHORE_MSG_QUEUE_SIZE); |
|
sem_wait(&s1); |
|
printf("Thread '%s' woke up.\n", (const char *) name); |
|
return NULL; |
|
} |
|
|
|
char names[SEMAPHORE_TEST_THREADS][16]; |
|
void test2(void) |
|
{ |
|
puts("first: sem_init"); |
|
|
|
if (sem_init(&s1, 0, 0) < 0) { |
|
puts("first: sem_init FAILED"); |
|
} |
|
|
|
for (int i = 0; i < SEMAPHORE_TEST_THREADS; i++) { |
|
int priority = THREAD_PRIORITY_MAIN - (i + 3) % 10 + 1; |
|
|
|
snprintf(names[i], sizeof(names[i]), "priority %d", priority); |
|
printf("first: thread create: %d\n", priority); |
|
kernel_pid_t pid = thread_create(test2_thread_stack[i], |
|
sizeof(test2_thread_stack[i]), |
|
priority, |
|
THREAD_CREATE_STACKTEST, |
|
priority_sema_thread, |
|
names[i], |
|
names[i]); |
|
|
|
if (pid == KERNEL_PID_UNDEF) { |
|
puts("first: thread create FAILED"); |
|
} |
|
|
|
printf("first: thread created: %s (%d/%d)\n", names[i], i + 1, SEMAPHORE_TEST_THREADS); |
|
} |
|
|
|
puts("------------------------------------------"); |
|
|
|
for (int i = 0; i < SEMAPHORE_TEST_THREADS; i++) { |
|
printf("post no. %d\n", i); |
|
sem_post(&s1); |
|
puts("Back in main thread."); |
|
} |
|
} |
|
|
|
static void *test3_one_two_thread(void *arg) |
|
{ |
|
msg_t msg_queue[SEMAPHORE_MSG_QUEUE_SIZE]; |
|
(void)arg; |
|
msg_init_queue(msg_queue, SEMAPHORE_MSG_QUEUE_SIZE); |
|
sem_wait(&s1); |
|
puts("Thread 1 woke up after waiting for s1."); |
|
sem_wait(&s2); |
|
puts("Thread 1 woke up after waiting for s2."); |
|
return NULL; |
|
} |
|
|
|
static void *test3_two_one_thread(void *arg) |
|
{ |
|
msg_t msg_queue[SEMAPHORE_MSG_QUEUE_SIZE]; |
|
(void)arg; |
|
msg_init_queue(msg_queue, SEMAPHORE_MSG_QUEUE_SIZE); |
|
sem_wait(&s2); |
|
puts("Thread 2 woke up after waiting for s2."); |
|
sem_wait(&s1); |
|
puts("Thread 2 woke up after waiting for s1."); |
|
return NULL; |
|
} |
|
|
|
void test3(void) |
|
{ |
|
puts("first: sem_init s1"); |
|
if (sem_init(&s1, 0, 0) < 0) { |
|
puts("first: sem_init FAILED"); |
|
} |
|
puts("first: sem_init s2"); |
|
if (sem_init(&s2, 0, 0) < 0) { |
|
puts("first: sem_init FAILED"); |
|
} |
|
puts("first: create thread 1"); |
|
if (thread_create(test2_thread_stack[0], sizeof(test2_thread_stack[0]), |
|
THREAD_PRIORITY_MAIN - 1, THREAD_CREATE_STACKTEST, |
|
test3_one_two_thread, NULL, "thread 1") < 0) { |
|
puts("first: thread create FAILED"); |
|
return; |
|
} |
|
puts("first: create thread 2"); |
|
if (thread_create(test2_thread_stack[1], sizeof(test2_thread_stack[1]), |
|
THREAD_PRIORITY_MAIN - 1, THREAD_CREATE_STACKTEST, |
|
test3_two_one_thread, NULL, "thread 2") < 0) { |
|
puts("first: thread create FAILED"); |
|
return; |
|
} |
|
puts("------------------------------------------"); |
|
puts("post s1"); |
|
sem_post(&s1); |
|
puts("post s2"); |
|
sem_post(&s2); |
|
puts("post s2"); |
|
sem_post(&s2); |
|
puts("post s1"); |
|
sem_post(&s1); |
|
} |
|
|
|
void test4(void) |
|
{ |
|
char uint64_str[20]; |
|
struct timespec abs; |
|
uint64_t now, start, stop; |
|
const uint64_t exp = 1000000; |
|
now = xtimer_now_usec64(); |
|
abs.tv_sec = (time_t)((now / US_PER_SEC) + 1); |
|
abs.tv_nsec = (long)((now % US_PER_SEC) * 1000); |
|
puts("first: sem_init s1"); |
|
if (sem_init(&s1, 0, 0) < 0) { |
|
puts("first: sem_init FAILED"); |
|
} |
|
start = xtimer_now_usec64(); |
|
puts("first: wait 1 sec for s1"); |
|
if (sem_timedwait(&s1, &abs) != 0) { |
|
if (errno != ETIMEDOUT) { |
|
printf("error waiting: %d\n", errno); |
|
return; |
|
} |
|
else { |
|
puts("first: timed out"); |
|
} |
|
} |
|
stop = xtimer_now_usec64() - start; |
|
if ((stop < (exp - 100)) || (stop > (exp + 100))) { |
|
fmt_u64_dec(uint64_str, stop); |
|
printf("first: waited only %s usec => FAILED\n", uint64_str); |
|
} |
|
else { |
|
fmt_u64_dec(uint64_str, stop); |
|
printf("first: waited %s usec\n", uint64_str); |
|
} |
|
} |
|
|
|
int main(void) |
|
{ |
|
msg_init_queue(main_msg_queue, SEMAPHORE_MSG_QUEUE_SIZE); |
|
xtimer_init(); |
|
puts("######################### TEST1:"); |
|
test1(); |
|
puts("######################### TEST2:"); |
|
test2(); |
|
puts("######################### TEST3:"); |
|
test3(); |
|
puts("######################### TEST4:"); |
|
test4(); |
|
puts("######################### DONE"); |
|
return 0; |
|
}
|
|
|