POSIX threads and semaphores

This patch implements a subset of the POSIX thread and semaphore functions
in the 'pthread' library.

Fixes #174.
This commit is contained in:
Christian Prochaska 2012-04-12 11:59:29 +02:00 committed by Norman Feske
parent dd0ef3403f
commit ff3e08f9ea
6 changed files with 374 additions and 0 deletions

View File

@ -0,0 +1,8 @@
SRC_CC = semaphore.cc \
thread.cc
LIBS += libc
vpath % $(REP_DIR)/src/lib/pthread
SHARED_LIB = yes

35
libports/run/pthread.run Normal file
View File

@ -0,0 +1,35 @@
build "core init test/pthread"
create_boot_directory
install_config {
<config>
<parent-provides>
<service name="ROM"/>
<service name="RAM"/>
<service name="IRQ"/>
<service name="IO_MEM"/>
<service name="IO_PORT"/>
<service name="CAP"/>
<service name="PD"/>
<service name="RM"/>
<service name="CPU"/>
<service name="LOG"/>
</parent-provides>
<default-route>
<any-service> <parent/> <any-child/> </any-service>
</default-route>
<start name="test-pthread">
<resource name="RAM" quantum="2M"/>
</start>
</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

View File

@ -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 <base/printf.h>
#include <os/timed_semaphore.h>
#include <semaphore.h>
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;
}
}

View File

@ -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 <base/env.h>
#include <base/printf.h>
#include <base/sleep.h>
#include <base/thread.h>
#include <errno.h>
#include <pthread.h>
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<STACK_SIZE>
{
void *(*_start_routine) (void *);
void *_arg;
pthread(void *(*start_routine) (void *), void *arg)
: Thread<STACK_SIZE>("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<pthread_t>(Thread_base::myself());
/* the main thread does not have a Genode thread object */
return thread ? thread : &main_thread;
}
}

View File

@ -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 <pthread.h>
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
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;
}

View File

@ -0,0 +1,3 @@
TARGET = test-pthread
SRC_CC = main.cc
LIBS = libc libc_log pthread