mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-31 08:25:38 +00:00
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:
parent
dd0ef3403f
commit
ff3e08f9ea
8
libports/lib/mk/pthread.mk
Normal file
8
libports/lib/mk/pthread.mk
Normal 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
35
libports/run/pthread.run
Normal 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
|
103
libports/src/lib/pthread/semaphore.cc
Normal file
103
libports/src/lib/pthread/semaphore.cc
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
93
libports/src/lib/pthread/thread.cc
Normal file
93
libports/src/lib/pthread/thread.cc
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
132
libports/src/test/pthread/main.cc
Normal file
132
libports/src/test/pthread/main.cc
Normal 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;
|
||||||
|
}
|
3
libports/src/test/pthread/target.mk
Normal file
3
libports/src/test/pthread/target.mk
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
TARGET = test-pthread
|
||||||
|
SRC_CC = main.cc
|
||||||
|
LIBS = libc libc_log pthread
|
Loading…
x
Reference in New Issue
Block a user