diff options
Diffstat (limited to 'src/init')
-rw-r--r-- | src/init/lib/esemaphore.c | 55 | ||||
-rw-r--r-- | src/init/lib/esemaphore.h | 12 | ||||
-rw-r--r-- | src/init/tests/main.c | 1 | ||||
-rw-r--r-- | src/init/tests/main.h | 1 | ||||
-rw-r--r-- | src/init/tests/pipe.c | 2 | ||||
-rw-r--r-- | src/init/tests/semaphore.c | 70 |
6 files changed, 139 insertions, 2 deletions
diff --git a/src/init/lib/esemaphore.c b/src/init/lib/esemaphore.c new file mode 100644 index 0000000..ac65b02 --- /dev/null +++ b/src/init/lib/esemaphore.c @@ -0,0 +1,55 @@ +#include <init/lib/esemaphore.h> +#include <init/stdlib.h> +#include <shared/flags.h> +#include <shared/syscalls.h> + +void esem_signal(struct evil_sem *sem) { + _syscall_write(sem->signal, NULL, 0, 0); +} + +void esem_wait(struct evil_sem *sem) { + _syscall_read(sem->wait, NULL, 0, 0); +} + +struct evil_sem *esem_new(int value) { + handle_t ends_wait[2], ends_signal[2]; + struct evil_sem *sem; + + if (value < 0) return NULL; + if (_syscall_pipe(ends_wait, 0) < 0) return NULL; + if (_syscall_pipe(ends_signal, 0) < 0) goto fail_signal; + if (!(sem = malloc(sizeof *sem))) goto fail_malloc; + + if (!_syscall_fork(FORK_NOREAP, NULL)) { + _syscall_close(ends_signal[1]); + while (_syscall_read(ends_signal[0], NULL, 0, 0) >= 0) { + if (!_syscall_fork(FORK_NOREAP, NULL)) { + _syscall_write(ends_wait[1], NULL, 0, 0); + _syscall_exit(0); + } + } + _syscall_exit(0); + } + _syscall_close(ends_signal[0]); + _syscall_close(ends_wait[1]); + + sem->wait = ends_wait[0]; + sem->signal = ends_signal[1]; + + while (value--) esem_signal(sem); + return sem; + +fail_malloc: + _syscall_close(ends_signal[0]); + _syscall_close(ends_signal[1]); +fail_signal: + _syscall_close(ends_wait[0]); + _syscall_close(ends_wait[1]); + return NULL; +} + +void esem_free(struct evil_sem *sem) { + _syscall_close(sem->wait); + _syscall_close(sem->signal); + free(sem); +} diff --git a/src/init/lib/esemaphore.h b/src/init/lib/esemaphore.h new file mode 100644 index 0000000..e746bd7 --- /dev/null +++ b/src/init/lib/esemaphore.h @@ -0,0 +1,12 @@ +#pragma once +#include <shared/types.h> + +struct evil_sem { + handle_t wait, signal; +}; + +void esem_signal(struct evil_sem *sem); +void esem_wait(struct evil_sem *sem); + +struct evil_sem *esem_new(int value); +void esem_free(struct evil_sem *sem); diff --git a/src/init/tests/main.c b/src/init/tests/main.c index f0845fe..9adb50c 100644 --- a/src/init/tests/main.c +++ b/src/init/tests/main.c @@ -146,5 +146,6 @@ void test_all(void) { run_forked(test_memflag); run_forked(test_malloc); run_forked(test_pipe); + run_forked(test_semaphore); run_forked(test_misc); } diff --git a/src/init/tests/main.h b/src/init/tests/main.h index 47c2507..ed11c5e 100644 --- a/src/init/tests/main.h +++ b/src/init/tests/main.h @@ -4,6 +4,7 @@ void stress_all(void); void test_all(void); void test_pipe(void); +void test_semaphore(void); #ifdef TEST_MACROS diff --git a/src/init/tests/pipe.c b/src/init/tests/pipe.c index a980cb8..8e9d243 100644 --- a/src/init/tests/pipe.c +++ b/src/init/tests/pipe.c @@ -113,6 +113,4 @@ void test_pipe(void) { // not a to.do detect when all processes that can read are stuck on writing to the pipe and vice versa // it seems like linux just lets the process hang endlessly. - - // TODO kill process that's waiting on a pipe } diff --git a/src/init/tests/semaphore.c b/src/init/tests/semaphore.c new file mode 100644 index 0000000..e542f0b --- /dev/null +++ b/src/init/tests/semaphore.c @@ -0,0 +1,70 @@ +#define TEST_MACROS +#include <init/lib/esemaphore.h> +#include <init/stdlib.h> +#include <init/tests/main.h> +#include <shared/flags.h> +#include <shared/syscalls.h> + +static void odd(struct evil_sem *sem1, struct evil_sem *sem2) { + printf("1"); + esem_signal(sem1); + + esem_wait(sem2); + printf("3"); + esem_signal(sem1); + + esem_wait(sem2); + printf("5"); + esem_signal(sem1); +} + +static void even(struct evil_sem *sem1, struct evil_sem *sem2) { + esem_wait(sem1); + printf("2"); + esem_signal(sem2); + + esem_wait(sem1); + printf("4"); + esem_signal(sem2); + + esem_wait(sem1); + printf("6"); + esem_signal(sem2); +} + +void test_semaphore(void) { + struct evil_sem *sem1, *sem2; + + // TODO pipe-based test + + sem1 = esem_new(0); + sem2 = esem_new(0); + assert(sem1 && sem2); + if (!_syscall_fork(0, NULL)) { + odd(sem1, sem2); + _syscall_exit(69); + } else { + even(sem1, sem2); + assert(_syscall_await() == 69); + } + esem_free(sem1); + esem_free(sem2); + + printf("\n"); + + sem1 = esem_new(0); + sem2 = esem_new(0); + assert(sem1 && sem2); + if (!_syscall_fork(0, NULL)) { + even(sem1, sem2); + _syscall_exit(69); + } else { + odd(sem1, sem2); + assert(_syscall_await() == 69); + _syscall_await(); + } + esem_free(sem1); + esem_free(sem2); + + printf("\n"); +} |