diff --git a/libports/lib/mk/pthread.mk b/libports/lib/mk/pthread.mk new file mode 100644 index 0000000000..543c1821a3 --- /dev/null +++ b/libports/lib/mk/pthread.mk @@ -0,0 +1,8 @@ +SRC_CC = semaphore.cc \ + thread.cc + +LIBS += libc + +vpath % $(REP_DIR)/src/lib/pthread + +SHARED_LIB = yes diff --git a/libports/run/pthread.run b/libports/run/pthread.run new file mode 100644 index 0000000000..61caff38c1 --- /dev/null +++ b/libports/run/pthread.run @@ -0,0 +1,35 @@ +build "core init test/pthread" + +create_boot_directory + +install_config { + + + + + + + + + + + + + + + + + + + + +} + +build_boot_image { + core init test-pthread + ld.lib.so libc.lib.so libc_log.lib.so pthread.lib.so +} + +append qemu_args " -nographic -m 64 " + +run_genode_until "--- returning from main ---" 10 diff --git a/libports/src/lib/pthread/semaphore.cc b/libports/src/lib/pthread/semaphore.cc new file mode 100644 index 0000000000..d95af43d24 --- /dev/null +++ b/libports/src/lib/pthread/semaphore.cc @@ -0,0 +1,103 @@ +/* + * \brief POSIX semaphore implementation + * \author Christian Prochaska + * \date 2012-03-12 + * + */ + +/* + * Copyright (C) 2012 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#include +#include + +#include + +using namespace Genode; + +extern "C" { + + /* + * This class is named 'struct sem' because the 'sem_t' type is + * defined as 'struct sem*' in 'semaphore.h' + */ + struct sem : Timed_semaphore + { + sem(int value) : Timed_semaphore(value) { } + }; + + + int sem_close(sem_t *) + { + PDBG("not implemented"); + return -1; + } + + + int sem_destroy(sem_t *sem) + { + destroy(env()->heap(), *sem); + return 0; + } + + + int sem_getvalue(sem_t * __restrict sem, int * __restrict sval) + { + *sval = (*sem)->cnt(); + return 0; + } + + + int sem_init(sem_t *sem, int pshared, unsigned int value) + { + *sem = new (env()->heap()) struct sem(value); + return 0; + } + + + sem_t *sem_open(const char *, int, ...) + { + PDBG("not implemented"); + return 0; + } + + + int sem_post(sem_t *sem) + { + (*sem)->up(); + return 0; + } + + + int sem_timedwait(sem_t * __restrict, const struct timespec * __restrict) + { + PDBG("not implemented"); + return -1; + } + + + int sem_trywait(sem_t *) + { + PDBG("not implemented"); + return -1; + } + + + int sem_unlink(const char *) + { + PDBG("not implemented"); + return -1; + } + + + int sem_wait(sem_t *sem) + { + (*sem)->down(); + return 0; + } + +} diff --git a/libports/src/lib/pthread/thread.cc b/libports/src/lib/pthread/thread.cc new file mode 100644 index 0000000000..1b628905b1 --- /dev/null +++ b/libports/src/lib/pthread/thread.cc @@ -0,0 +1,93 @@ +/* + * \brief POSIX thread implementation + * \author Christian Prochaska + * \date 2012-03-12 + * + */ + +/* + * Copyright (C) 2012 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#include +#include +#include +#include + +#include +#include + +using namespace Genode; + +extern "C" { + + enum { STACK_SIZE=64*1024 }; + + /* + * This class is named 'struct pthread' because the 'pthread_t' type is + * defined as 'struct pthread*' in '_pthreadtypes.h' + */ + struct pthread : Thread + { + void *(*_start_routine) (void *); + void *_arg; + + pthread(void *(*start_routine) (void *), void *arg) + : Thread("pthread"), + _start_routine(start_routine), + _arg(arg) { } + + void entry() + { + void *exit_status = _start_routine(_arg); + pthread_exit(exit_status); + } + }; + + + int pthread_create(pthread_t *thread, const pthread_attr_t *attr, + void *(*start_routine) (void *), void *arg) + { + pthread_t thread_obj = new (env()->heap()) pthread(start_routine, arg); + + if (!thread_obj) { + errno = EAGAIN; + return -1; + } + + *thread = thread_obj; + + thread_obj->start(); + + return 0; + } + + + int pthread_cancel(pthread_t thread) + { + destroy(env()->heap(), thread); + return 0; + } + + + void pthread_exit(void *value_ptr) + { + pthread_cancel(pthread_self()); + sleep_forever(); + } + + + pthread_t pthread_self(void) + { + static struct pthread main_thread(0, 0); + + pthread_t thread = static_cast(Thread_base::myself()); + + /* the main thread does not have a Genode thread object */ + return thread ? thread : &main_thread; + } + +} diff --git a/libports/src/test/pthread/main.cc b/libports/src/test/pthread/main.cc new file mode 100644 index 0000000000..45696793b5 --- /dev/null +++ b/libports/src/test/pthread/main.cc @@ -0,0 +1,132 @@ +/* + * \brief POSIX thread and semaphore test + * \author Christian Prochaska + * \date 2012-04-04 + */ + +/* + * Copyright (C) 2012 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#include +#include +#include +#include + + +enum { NUM_THREADS = 2 }; + + +struct Thread_args { + int thread_num; + sem_t thread_finished_sem; + pthread_t thread_id_self; /* thread ID returned by 'pthread_self()' */ +}; + + +struct Thread { + Thread_args thread_args; + pthread_t thread_id_create; /* thread ID returned by 'pthread_create()' */ +}; + + +void *thread_func(void *arg) +{ + Thread_args *thread_args = (Thread_args*)arg; + + printf("thread %d: running, my thread ID is %p\n", + thread_args->thread_num, pthread_self()); + + thread_args->thread_id_self = pthread_self(); + + sem_post(&thread_args->thread_finished_sem); + + /* sleep forever */ + sem_t sleep_sem; + sem_init(&sleep_sem, 0, 0); + sem_wait(&sleep_sem); + + return 0; +} + +static inline void compare_semaphore_values(int reported_value, int expected_value) +{ + if (reported_value != expected_value) { + printf("error: sem_getvalue() did not return the expected value\n"); + exit(-1); + } +} + + +int main(int argc, char **argv) +{ + printf("--- pthread test ---\n"); + + printf("main thread: running, my thread ID is %p\n", pthread_self()); + + Thread thread[NUM_THREADS]; + + for (int i = 0; i < NUM_THREADS; i++) { + thread[i].thread_args.thread_num = i + 1; + + printf("main thread: creating semaphore for thread %d\n", + thread[i].thread_args.thread_num); + + if (sem_init(&thread[i].thread_args.thread_finished_sem, 0, 1) != 0) { + printf("sem_init() failed\n"); + return -1; + } + + /* check result of 'sem_getvalue()' before and after calling 'sem_wait()' */ + + int sem_value = -1; + + sem_getvalue(&thread[i].thread_args.thread_finished_sem, &sem_value); + compare_semaphore_values(sem_value, 1); + + sem_wait(&thread[i].thread_args.thread_finished_sem); + + sem_getvalue(&thread[i].thread_args.thread_finished_sem, &sem_value); + compare_semaphore_values(sem_value, 0); + + thread[i].thread_args.thread_id_self = 0; + + printf("main thread: creating thread %d\n", thread[i].thread_args.thread_num); + + if (pthread_create(&thread[i].thread_id_create, 0, thread_func, + &thread[i].thread_args) != 0) { + printf("error: pthread_create() failed\n"); + return -1; + } + printf("main thread: thread %d has thread ID %p\n", + thread[i].thread_args.thread_num, thread[i].thread_id_create); + } + + printf("main thread: waiting for the threads to finish\n"); + + for (int i = 0; i < NUM_THREADS; i++) + sem_wait(&thread[i].thread_args.thread_finished_sem); + + printf("main thread: comparing the thread IDs\n"); + + for (int i = 0; i < NUM_THREADS; i++) + if (thread[i].thread_args.thread_id_self != thread[i].thread_id_create) { + printf("error: thread IDs don't match\n"); + } + + printf("main thread: destroying the threads\n"); + + for (int i = 0; i < NUM_THREADS; i++) + pthread_cancel(thread[i].thread_id_create); + + printf("main thread: destroying the semaphores\n"); + + for (int i = 0; i < NUM_THREADS; i++) + sem_destroy(&thread[i].thread_args.thread_finished_sem); + + printf("--- returning from main ---\n"); + return 0; +} diff --git a/libports/src/test/pthread/target.mk b/libports/src/test/pthread/target.mk new file mode 100644 index 0000000000..40c7c2c136 --- /dev/null +++ b/libports/src/test/pthread/target.mk @@ -0,0 +1,3 @@ +TARGET = test-pthread +SRC_CC = main.cc +LIBS = libc libc_log pthread