
17 changed files with 1083 additions and 0 deletions
@ -0,0 +1,7 @@
|
||||
MODULE = pthread
|
||||
|
||||
CFLAGS += -isystem $(RIOTBASE)/sys/posix/pthread/include
|
||||
|
||||
export INCLUDES += -I$(RIOTBASE)/sys/posix/pthread/include
|
||||
|
||||
include $(RIOTBASE)/Makefile.base |
@ -0,0 +1,99 @@
|
||||
#ifndef RIOT_PTHREAD_H |
||||
#define RIOT_PTHREAD_H 1 |
||||
|
||||
#include <time.h> |
||||
|
||||
#include "kernel.h" |
||||
#include "mutex.h" |
||||
#include "sched.h" |
||||
|
||||
#include "pthreadtypes.h" |
||||
|
||||
/* Create a new thread, starting with execution of START-ROUTINE
|
||||
getting passed ARG. Creation attributed come from ATTR. The new |
||||
handle is stored in *NEWTHREAD. */ |
||||
int pthread_create(pthread_t *newthread, const pthread_attr_t *attr, |
||||
void *(*start_routine)(void *), void *arg); |
||||
|
||||
/* Terminate calling thread.
|
||||
|
||||
The registered cleanup handlers are called via exception handling .*/ |
||||
void pthread_exit(void *retval); |
||||
|
||||
/* Make calling thread wait for termination of the thread TH. The
|
||||
exit status of the thread is stored in *THREAD_RETURN, if THREAD_RETURN |
||||
is not NULL. |
||||
|
||||
This function is a cancellation point and therefore not marked with |
||||
. */ |
||||
int pthread_join(pthread_t th, void **thread_return); |
||||
|
||||
/* Indicate that the thread TH is never to be joined with PTHREAD_JOIN.
|
||||
The resources of TH will therefore be freed immediately when it |
||||
terminates, instead of waiting for another thread to perform PTHREAD_JOIN |
||||
on it. */ |
||||
int pthread_detach(pthread_t th); |
||||
|
||||
/* Obtain the identifier of the current thread. */ |
||||
pthread_t pthread_self(void); |
||||
|
||||
/* Compare two thread identifiers. */ |
||||
int pthread_equal(pthread_t thread1, pthread_t thread2); |
||||
|
||||
#include "pthread_attr.h" |
||||
|
||||
/* Functions for scheduling control. */ |
||||
|
||||
/* Set the scheduling parameters for TARGET_THREAD according to POLICY
|
||||
and *PARAM. */ |
||||
int pthread_setschedparam(pthread_t target_thread, int policy, |
||||
const struct sched_param *param); |
||||
|
||||
/* Return in *POLICY and *PARAM the scheduling parameters for TARGET_THREAD. */ |
||||
int pthread_getschedparam(pthread_t target_thread, int *policy, |
||||
struct sched_param *param); |
||||
|
||||
/* Set the scheduling priority for TARGET_THREAD. */ |
||||
int pthread_setschedprio(pthread_t target_thread, int prio); |
||||
|
||||
/* Functions for handling initialization. */ |
||||
|
||||
/* Guarantee that the initialization function INIT_ROUTINE will be called
|
||||
only once, even if pthread_once is executed several times with the |
||||
same ONCE_CONTROL argument. ONCE_CONTROL must point to a static or |
||||
variable initialized to PTHREAD_ONCE_INIT. |
||||
|
||||
The initialization functions might throw exception */ |
||||
int pthread_once(pthread_once_t *once_control, void (*init_routine)(void)); |
||||
|
||||
/* Functions for handling cancellation.
|
||||
|
||||
Note that these functions are explicitly not marked to not throw an |
||||
exception in C++ code. If cancellation is implemented by unwinding |
||||
this is necessary to have the compiler generate the unwind information. */ |
||||
|
||||
/* Set cancelability state of current thread to STATE, returning old
|
||||
state in *OLDSTATE if OLDSTATE is not NULL. */ |
||||
int pthread_setcancelstate(int state, int *oldstate); |
||||
|
||||
/* Set cancellation state of current thread to TYPE, returning the old
|
||||
type in *OLDTYPE if OLDTYPE is not NULL. */ |
||||
int pthread_setcanceltype(int type, int *oldtype); |
||||
|
||||
/* Cancel THREAD immediately or at the next possibility. */ |
||||
int pthread_cancel(pthread_t th); |
||||
|
||||
/* Test for pending cancellation for the current thread and terminate
|
||||
the thread as per pthread_exit(PTHREAD_CANCELED) if it has been |
||||
cancelled. */ |
||||
void pthread_testcancel(void); |
||||
|
||||
#include "pthread_mutex.h" |
||||
|
||||
#include "pthread_rwlock.h" |
||||
|
||||
#include "pthread_spin.h" |
||||
|
||||
#include "pthread_barrier.h" |
||||
|
||||
#endif /* pthread.h */ |
@ -0,0 +1,67 @@
|
||||
/* Thread attribute handling. */ |
||||
|
||||
#define PTHREAD_CREATE_DETACHED (1) |
||||
#define PTHREAD_CREATE_JOINABLE (0) |
||||
|
||||
/* Initialize thread attribute *ATTR with default attributes
|
||||
(detachstate is PTHREAD_JOINABLE, scheduling policy is SCHED_OTHER, |
||||
no user-provided stack). */ |
||||
int pthread_attr_init(pthread_attr_t *attr); |
||||
|
||||
/* Destroy thread attribute *ATTR. */ |
||||
int pthread_attr_destroy(pthread_attr_t *attr); |
||||
|
||||
/* Get detach state attribute. */ |
||||
int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate); |
||||
|
||||
/* Set detach state attribute. */ |
||||
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate); |
||||
|
||||
/* Get the size of the guard area created for stack overflow protection. */ |
||||
int pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize); |
||||
|
||||
/* Set the size of the guard area created for stack overflow protection. */ |
||||
int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize); |
||||
|
||||
/* Return in *PARAM the scheduling parameters of *ATTR. */ |
||||
int pthread_attr_getschedparam(const pthread_attr_t *attr, |
||||
struct sched_param *param); |
||||
|
||||
/* Set scheduling parameters (priority, etc) in *ATTR according to PARAM. */ |
||||
int pthread_attr_setschedparam(pthread_attr_t *attr, |
||||
const struct sched_param *param); |
||||
|
||||
/* Return in *POLICY the scheduling policy of *ATTR. */ |
||||
int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy); |
||||
|
||||
/* Set scheduling policy in *ATTR according to POLICY. */ |
||||
int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy); |
||||
|
||||
/* Return in *INHERIT the scheduling inheritance mode of *ATTR. */ |
||||
int pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inherit); |
||||
|
||||
/* Set scheduling inheritance mode in *ATTR according to INHERIT. */ |
||||
int pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit); |
||||
|
||||
/* Return in *SCOPE the scheduling contention scope of *ATTR. */ |
||||
int pthread_attr_getscope(const pthread_attr_t *attr, int *scope); |
||||
|
||||
/* Set scheduling contention scope in *ATTR according to SCOPE. */ |
||||
int pthread_attr_setscope(pthread_attr_t *attr, int scope); |
||||
|
||||
/* Return the previously set address for the stack. */ |
||||
int pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr); |
||||
|
||||
/* Set the starting address of the stack of the thread to be created.
|
||||
Depending on whether the stack grows up or down the value must either |
||||
be higher or lower than all the address in the memory block. The |
||||
minimal size of the block must be PTHREAD_STACK_MIN. */ |
||||
int pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr); |
||||
|
||||
/* Return the currently used minimal stack size. */ |
||||
int pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize); |
||||
|
||||
/* Add information about the minimum stack size needed for the thread
|
||||
to be started. This size must never be less than PTHREAD_STACK_MIN |
||||
and must also not exceed the system limits. */ |
||||
int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize); |
@ -0,0 +1,25 @@
|
||||
/* Functions to handle barriers. */ |
||||
|
||||
/* Initialize BARRIER with the attributes in ATTR. The barrier is
|
||||
opened when COUNT waiters arrived. */ |
||||
int pthread_barrier_init(pthread_barrier_t *barrier, |
||||
const pthread_barrierattr_t *attr, unsigned int count); |
||||
|
||||
/* Destroy a previously dynamically initialized barrier BARRIER. */ |
||||
int pthread_barrier_destroy(pthread_barrier_t *barrier); |
||||
|
||||
/* Wait on barrier BARRIER. */ |
||||
int pthread_barrier_wait(pthread_barrier_t *barrier); |
||||
|
||||
/* Initialize barrier attribute ATTR. */ |
||||
int pthread_barrierattr_init(pthread_barrierattr_t *attr); |
||||
|
||||
/* Destroy previously dynamically initialized barrier attribute ATTR. */ |
||||
int pthread_barrierattr_destroy(pthread_barrierattr_t *attr); |
||||
|
||||
/* Get the process-shared flag of the barrier attribute ATTR. */ |
||||
int pthread_barrierattr_getpshared(const pthread_barrierattr_t *attr, |
||||
int *pshared); |
||||
|
||||
/* Set the process-shared flag of the barrier attribute ATTR. */ |
||||
int pthread_barrierattr_setpshared(pthread_barrierattr_t *attr, int pshared); |
@ -0,0 +1,51 @@
|
||||
/* Functions for handling conditional variables. */ |
||||
|
||||
/* Initialize condition variable COND using attributes ATTR, or use
|
||||
the default values if later is NULL. */ |
||||
int pthread_cond_init(pthread_cond_t *cond, |
||||
const pthread_condattr_t *cond_attr); |
||||
|
||||
/* Destroy condition variable COND. */ |
||||
int pthread_cond_destroy(pthread_cond_t *cond); |
||||
|
||||
/* Wake up one thread waiting for condition variable COND. */ |
||||
int pthread_cond_signal(pthread_cond_t *cond); |
||||
|
||||
/* Wake up all threads waiting for condition variables COND. */ |
||||
int pthread_cond_broadcast(pthread_cond_t *cond); |
||||
|
||||
/* Wait for condition variable COND to be signaled or broadcast.
|
||||
MUTEX is assumed to be locked before. |
||||
|
||||
This function is a cancellation point and therefore not marked with. */ |
||||
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); |
||||
|
||||
/* Wait for condition variable COND to be signaled or broadcast until
|
||||
ABSTIME. MUTEX is assumed to be locked before. ABSTIME is an |
||||
absolute time specification; zero is the beginning of the epoch |
||||
(00:00:00 GMT, January 1, 1970). |
||||
|
||||
This function is a cancellation point and therefore not marked with. */ |
||||
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, |
||||
const struct timespec *abstime); |
||||
|
||||
/* Functions for handling condition variable attributes. */ |
||||
|
||||
/* Initialize condition variable attribute ATTR. */ |
||||
int pthread_condattr_init(pthread_condattr_t *attr); |
||||
|
||||
/* Destroy condition variable attribute ATTR. */ |
||||
int pthread_condattr_destroy(pthread_condattr_t *attr); |
||||
|
||||
/* Get the process-shared flag of the condition variable attribute ATTR. */ |
||||
int pthread_condattr_getpshared(const pthread_condattr_t *attr, int *pshared); |
||||
|
||||
/* Set the process-shared flag of the condition variable attribute ATTR. */ |
||||
int pthread_condattr_setpshared(pthread_condattr_t *attr, int pshared); |
||||
|
||||
/* Get the clock selected for the conditon variable attribute ATTR. */ |
||||
int pthread_condattr_getclock(const pthread_condattr_t *attr, |
||||
clockid_t *clock_id); |
||||
|
||||
/* Set the clock selected for the conditon variable attribute ATTR. */ |
||||
int pthread_condattr_setclock(pthread_condattr_t *attr, clockid_t clock_id); |
@ -0,0 +1,81 @@
|
||||
/* Mutex handling. */ |
||||
|
||||
#include <time.h> |
||||
|
||||
#include "kernel.h" |
||||
#include "mutex.h" |
||||
|
||||
/* Initialize a mutex. */ |
||||
int pthread_mutex_init(pthread_mutex_t *mutex, |
||||
const pthread_mutexattr_t *mutexattr); |
||||
|
||||
/* Destroy a mutex. */ |
||||
int pthread_mutex_destroy(pthread_mutex_t *mutex); |
||||
|
||||
/* Try locking a mutex. */ |
||||
int pthread_mutex_trylock(pthread_mutex_t *mutex); |
||||
|
||||
/* Lock a mutex. */ |
||||
int pthread_mutex_lock(pthread_mutex_t *mutex); |
||||
|
||||
/* Wait until lock becomes available, or specified time passes. */ |
||||
int pthread_mutex_timedlock(pthread_mutex_t *mutex, |
||||
const struct timespec *abstime); |
||||
|
||||
/* Unlock a mutex. */ |
||||
int pthread_mutex_unlock(pthread_mutex_t *mutex); |
||||
|
||||
/* Get the priority ceiling of MUTEX. */ |
||||
int pthread_mutex_getprioceiling(const pthread_mutex_t *mutex, |
||||
int *prioceiling); |
||||
|
||||
/* Set the priority ceiling of MUTEX to PRIOCEILING, return old
|
||||
priority ceiling value in *OLD_CEILING. */ |
||||
int pthread_mutex_setprioceiling(pthread_mutex_t *mutex, int prioceiling, |
||||
int *old_ceiling); |
||||
|
||||
/* Functions for handling mutex attributes. */ |
||||
|
||||
/* Initialize mutex attribute object ATTR with default attributes
|
||||
(kind is PTHREAD_MUTEX_TIMED_NP). */ |
||||
int pthread_mutexattr_init(pthread_mutexattr_t *attr); |
||||
|
||||
/* Destroy mutex attribute object ATTR. */ |
||||
int pthread_mutexattr_destroy(pthread_mutexattr_t *attr); |
||||
|
||||
/* Get the process-shared flag of the mutex attribute ATTR. */ |
||||
int pthread_mutexattr_getpshared(const pthread_mutexattr_t *attr, |
||||
int *pshared); |
||||
|
||||
/* Set the process-shared flag of the mutex attribute ATTR. */ |
||||
int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared); |
||||
|
||||
/* Return in *KIND the mutex kind attribute in *ATTR. */ |
||||
int pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *kind); |
||||
|
||||
/* Set the mutex kind attribute in *ATTR to KIND (either PTHREAD_MUTEX_NORMAL,
|
||||
PTHREAD_MUTEX_RECURSIVE, PTHREAD_MUTEX_ERRORCHECK, or |
||||
PTHREAD_MUTEX_DEFAULT). */ |
||||
int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int kind); |
||||
|
||||
/* Return in *PROTOCOL the mutex protocol attribute in *ATTR. */ |
||||
int pthread_mutexattr_getprotocol(const pthread_mutexattr_t *attr, |
||||
int *protocol); |
||||
|
||||
/* Set the mutex protocol attribute in *ATTR to PROTOCOL (either
|
||||
PTHREAD_PRIO_NONE, PTHREAD_PRIO_INHERIT, or PTHREAD_PRIO_PROTECT). */ |
||||
int pthread_mutexattr_setprotocol(pthread_mutexattr_t *attr, int protocol); |
||||
|
||||
/* Return in *PRIOCEILING the mutex prioceiling attribute in *ATTR. */ |
||||
int pthread_mutexattr_getprioceiling(const pthread_mutexattr_t *attr, |
||||
int *prioceiling); |
||||
|
||||
/* Set the mutex prioceiling attribute in *ATTR to PRIOCEILING. */ |
||||
int pthread_mutexattr_setprioceiling(pthread_mutexattr_t *attr, int prioceiling); |
||||
|
||||
/* Get the robustness flag of the mutex attribute ATTR. */ |
||||
int pthread_mutexattr_getrobust(const pthread_mutexattr_t *attr, |
||||
int *robustness); |
||||
|
||||
/* Set the robustness flag of the mutex attribute ATTR. */ |
||||
int pthread_mutexattr_setrobust(pthread_mutexattr_t *attr, int robustness); |
@ -0,0 +1,53 @@
|
||||
/* Functions for handling read-write locks. */ |
||||
|
||||
/* Initialize read-write lock RWLOCK using attributes ATTR, or use
|
||||
the default values if later is NULL. */ |
||||
int pthread_rwlock_init(pthread_rwlock_t *rwlock, |
||||
const pthread_rwlockattr_t *attr); |
||||
|
||||
/* Destroy read-write lock RWLOCK. */ |
||||
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock); |
||||
|
||||
/* Acquire read lock for RWLOCK. */ |
||||
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock); |
||||
|
||||
/* Try to acquire read lock for RWLOCK. */ |
||||
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock); |
||||
|
||||
/* Try to acquire read lock for RWLOCK or return after specfied time. */ |
||||
int pthread_rwlock_timedrdlock(pthread_rwlock_t *rwlock, |
||||
const struct timespec *abstime); |
||||
|
||||
/* Acquire write lock for RWLOCK. */ |
||||
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock); |
||||
|
||||
/* Try to acquire write lock for RWLOCK. */ |
||||
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock); |
||||
|
||||
/* Try to acquire write lock for RWLOCK or return after specfied time. */ |
||||
int pthread_rwlock_timedwrlock(pthread_rwlock_t *rwlock, |
||||
const struct timespec *abstime); |
||||
|
||||
/* Unlock RWLOCK. */ |
||||
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock); |
||||
|
||||
/* Functions for handling read-write lock attributes. */ |
||||
|
||||
/* Initialize attribute object ATTR with default values. */ |
||||
int pthread_rwlockattr_init(pthread_rwlockattr_t *attr); |
||||
|
||||
/* Destroy attribute object ATTR. */ |
||||
int pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr); |
||||
|
||||
/* Return current setting of process-shared attribute of ATTR in PSHARED. */ |
||||
int pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *attr, |
||||
int *pshared); |
||||
|
||||
/* Set process-shared attribute of ATTR to PSHARED. */ |
||||
int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *attr, int pshared); |
||||
|
||||
/* Return current setting of reader/writer preference. */ |
||||
int pthread_rwlockattr_getkind_np(const pthread_rwlockattr_t *attr, int *pref); |
||||
|
||||
/* Set reader/write preference. */ |
||||
int pthread_rwlockattr_setkind_np(pthread_rwlockattr_t *attr, int pref); |
@ -0,0 +1,17 @@
|
||||
/* Functions to handle spinlocks. */ |
||||
|
||||
/* Initialize the spinlock LOCK. If PSHARED is nonzero the spinlock can
|
||||
be shared between different processes. */ |
||||
int pthread_spin_init(pthread_spinlock_t *lock, int pshared); |
||||
|
||||
/* Destroy the spinlock LOCK. */ |
||||
int pthread_spin_destroy(pthread_spinlock_t *lock); |
||||
|
||||
/* Wait until spinlock LOCK is retrieved. */ |
||||
int pthread_spin_lock(pthread_spinlock_t *lock); |
||||
|
||||
/* Try to lock spinlock LOCK. */ |
||||
int pthread_spin_trylock(pthread_spinlock_t *lock); |
||||
|
||||
/* Release spinlock LOCK. */ |
||||
int pthread_spin_unlock(pthread_spinlock_t *lock); |
@ -0,0 +1,36 @@
|
||||
#ifndef PTHREADTYPES_H_ |
||||
#define PTHREADTYPES_H_ |
||||
|
||||
typedef unsigned long int pthread_t; |
||||
|
||||
typedef struct pthread_attr |
||||
{ |
||||
uint8_t detached; |
||||
char *ss_sp; |
||||
size_t ss_size; |
||||
} pthread_attr_t; |
||||
|
||||
struct sched_param { |
||||
int todo; /* TODO */ |
||||
}; |
||||
|
||||
/* Once-only execution */ |
||||
typedef int pthread_once_t; |
||||
/* Single execution handling. */ |
||||
#define PTHREAD_ONCE_INIT 0 |
||||
|
||||
typedef unsigned long int pthread_barrier_t; |
||||
typedef unsigned long int pthread_barrierattr_t; |
||||
|
||||
typedef unsigned long int pthread_cond_t; |
||||
typedef unsigned long int pthread_condattr_t; |
||||
|
||||
typedef mutex_t pthread_mutex_t; |
||||
typedef unsigned long int pthread_mutexattr_t; |
||||
|
||||
typedef unsigned long int pthread_rwlock_t; |
||||
typedef unsigned long int pthread_rwlockattr_t; |
||||
|
||||
typedef volatile int pthread_spinlock_t; |
||||
|
||||
#endif /* PTHREADTYPES_H_ */ |
@ -0,0 +1,282 @@
|
||||
/**
|
||||
* POSIX implementation of threading. |
||||
* |
||||
* Copyright (C) 2013 Freie Universität Berlin |
||||
* |
||||
* This file subject to the terms and conditions of the GNU Lesser General |
||||
* Public License. See the file LICENSE in the top level directory for more |
||||
* details. |
||||
* |
||||
* @ingroup posix |
||||
* @{ |
||||
* @file pthread.c |
||||
* @brief Implementation of pthread. |
||||
* @author Christian Mehlis <mehlis@inf.fu-berlin.de> |
||||
* @author René Kijewski <kijewski@inf.fu-berlin.de> |
||||
* @} |
||||
*/ |
||||
|
||||
#include <malloc.h> |
||||
#include <stdbool.h> |
||||
#include <stddef.h> |
||||
#include <string.h> |
||||
|
||||
#include "cpu-conf.h" |
||||
#include "irq.h" |
||||
#include "kernel_internal.h" |
||||
#include "msg.h" |
||||
#include "mutex.h" |
||||
#include "queue.h" |
||||
#include "thread.h" |
||||
#include "sched.h" |
||||
|
||||
#include "pthread.h" |
||||
|
||||
#define ENABLE_DEBUG (1) |
||||
|
||||
#if ENABLE_DEBUG |
||||
#define PTHREAD_REAPER_STACKSIZE KERNEL_CONF_STACKSIZE_MAIN |
||||
#define PTHREAD_STACKSIZE KERNEL_CONF_STACKSIZE_MAIN |
||||
#else |
||||
#define PTHREAD_REAPER_STACKSIZE KERNEL_CONF_STACKSIZE_DEFAULT |
||||
#define PTHREAD_STACKSIZE KERNEL_CONF_STACKSIZE_DEFAULT |
||||
#endif |
||||
|
||||
#include "debug.h" |
||||
|
||||
enum pthread_thread_status { |
||||
PTS_RUNNING, |
||||
PTS_DETACHED, |
||||
PTS_ZOMBIE, |
||||
}; |
||||
|
||||
typedef struct pthread_thread { |
||||
enum pthread_thread_status status; |
||||
int joining_thread; |
||||
int thread_pid; |
||||
void *returnval; |
||||
bool should_cancel; |
||||
|
||||
void *(*start_routine)(void *); |
||||
void *arg; |
||||
|
||||
char *stack; |
||||
} pthread_thread_t; |
||||
|
||||
static pthread_thread_t *volatile pthread_sched_threads[MAXTHREADS]; |
||||
static struct mutex_t pthread_mutex; |
||||
|
||||
static volatile int pthread_reaper_pid = -1; |
||||
|
||||
char pthread_reaper_stack[PTHREAD_REAPER_STACKSIZE]; |
||||
|
||||
static void pthread_start_routine(void) |
||||
{ |
||||
pthread_t self = pthread_self(); |
||||
pthread_thread_t *pt = pthread_sched_threads[self]; |
||||
void *retval = pt->start_routine(pt->arg); |
||||
pthread_exit(retval); |
||||
} |
||||
|
||||
static int insert(pthread_thread_t *pt) |
||||
{ |
||||
int result = -1; |
||||
mutex_lock(&pthread_mutex); |
||||
for (int i = 0; i < MAXTHREADS; i++){ |
||||
if (!pthread_sched_threads[i]) { |
||||
pthread_sched_threads[i] = pt; |
||||
result = i; |
||||
break; |
||||
} |
||||
} |
||||
mutex_unlock(&pthread_mutex); |
||||
return result; |
||||
} |
||||
|
||||
static void pthread_reaper(void) |
||||
{ |
||||
while (1) { |
||||
msg_t m; |
||||
msg_receive(&m); |
||||
DEBUG("pthread_reaper(): free(%p)\n", m.content.ptr); |
||||
free(m.content.ptr); |
||||
} |
||||
} |
||||
|
||||
int pthread_create(pthread_t *newthread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg) |
||||
{ |
||||
pthread_thread_t *pt = calloc(1, sizeof(pthread_thread_t)); |
||||
|
||||
int pthread_pid = insert(pt); |
||||
if (pthread_pid < 0) { |
||||
free(pt); |
||||
return -1; |
||||
} |
||||
*newthread = pthread_pid; |
||||
|
||||
pt->status = attr && attr->detached ? PTS_DETACHED : PTS_RUNNING; |
||||
pt->start_routine = start_routine; |
||||
pt->arg = arg; |
||||
|
||||
bool autofree = attr == NULL || attr->ss_sp == NULL || attr->ss_size == 0; |
||||
size_t stack_size = attr && attr->ss_size > 0 ? attr->ss_size : PTHREAD_STACKSIZE; |
||||
void *stack = autofree ? malloc(stack_size) : attr->ss_sp; |
||||
pt->stack = autofree ? stack : NULL; |
||||
|
||||
if (autofree && pthread_reaper_pid < 0) { |
||||
mutex_lock(&pthread_mutex); |
||||
if (pthread_reaper_pid < 0) { |
||||
/* volatile pid to overcome problems with double checking */ |
||||
volatile int pid = thread_create(pthread_reaper_stack, |
||||
PTHREAD_REAPER_STACKSIZE, |
||||
0, |
||||
CREATE_STACKTEST, |
||||
pthread_reaper, |
||||
"pthread-reaper"); |
||||
pthread_reaper_pid = pid; |
||||
} |
||||
mutex_unlock(&pthread_mutex); |
||||
} |
||||
|
||||
pt->thread_pid = thread_create(stack, |
||||
stack_size, |
||||
PRIORITY_MAIN, |
||||
CREATE_WOUT_YIELD | CREATE_STACKTEST, |
||||
pthread_start_routine, |
||||
"pthread"); |
||||
if (pt->thread_pid < 0) { |
||||
free(pt->stack); |
||||
free(pt); |
||||
pthread_sched_threads[pthread_pid] = NULL; |
||||
return -1; |
||||
} |
||||
|
||||
sched_switch(active_thread->priority, PRIORITY_MAIN, inISR()); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
void pthread_exit(void *retval) |
||||
{ |
||||
pthread_thread_t *self = pthread_sched_threads[pthread_self()]; |
||||
DEBUG("pthread_exit(%p), self == %p\n", retval, (void *) self); |
||||
if (self->status != PTS_DETACHED) { |
||||
self->returnval = retval; |
||||
self->status = PTS_ZOMBIE; |
||||
|
||||
if (self->joining_thread) { |
||||
/* our thread got an other thread waiting for us */ |
||||
thread_wakeup(self->joining_thread); |
||||
} |
||||
} |
||||
|
||||
dINT(); |
||||
if (self->stack) { |
||||
msg_t m; |
||||
m.content.ptr = self->stack; |
||||
msg_send_int(&m, pthread_reaper_pid); |
||||
} |
||||
sched_task_exit(); |
||||
} |
||||
|
||||
int pthread_join(pthread_t th, void **thread_return) |
||||
{ |
||||
pthread_thread_t *other = pthread_sched_threads[th]; |
||||
if (!other) { |
||||
return -1; |
||||
} |
||||
|
||||
switch (other->status) { |
||||
case (PTS_RUNNING): |
||||
other->joining_thread = thread_pid; |
||||
/* go blocked, I'm waking up if other thread exits */ |
||||
thread_sleep(); |
||||
/* no break */ |
||||
case (PTS_ZOMBIE): |
||||
if (thread_return) { |
||||
*thread_return = other->returnval; |
||||
} |
||||
free(other); |
||||
/* we only need to free the pthread layer struct,
|
||||
native thread stack is freed by other */ |
||||
pthread_sched_threads[th] = NULL; |
||||
return 0; |
||||
case (PTS_DETACHED): |
||||
return -1; |
||||
} |
||||
|
||||
return -2; |
||||
} |
||||
|
||||
int pthread_detach(pthread_t th) |
||||
{ |
||||
pthread_thread_t *other = pthread_sched_threads[th]; |
||||
if (!other) { |
||||
return -1; |
||||
} |
||||
|
||||
if (other->status == PTS_ZOMBIE) { |
||||
free(other); |
||||
/* we only need to free the pthread layer struct,
|
||||
native thread stack is freed by other */ |
||||
pthread_sched_threads[th] = NULL; |
||||
} else { |
||||
other->status = PTS_DETACHED; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
pthread_t pthread_self(void) |
||||
{ |
||||
pthread_t result = -1; |
||||
mutex_lock(&pthread_mutex); |
||||
int pid = thread_pid; /* thread_pid is volatile */ |
||||
for (int i = 0; i < MAXTHREADS; i++) { |
||||
if (pthread_sched_threads[i] && pthread_sched_threads[i]->thread_pid == pid) { |
||||
result = i; |
||||
break; |
||||
} |
||||
} |
||||
mutex_unlock(&pthread_mutex); |
||||
return result; |
||||
} |
||||
|
||||
int pthread_equal(pthread_t thread1, pthread_t thread2) |
||||
{ |
||||
return (thread1 == thread2); |
||||
} |
||||
|
||||
int pthread_cancel(pthread_t th) |
||||
{ |
||||
pthread_thread_t *other = pthread_sched_threads[th]; |
||||
if (!other) { |
||||
return -1; |
||||
} |
||||
|
||||
other->should_cancel = 1; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int pthread_setcancelstate(int state, int *oldstate) |
||||
{ |
||||
(void) state; |
||||
(void) oldstate; |
||||
return 0; |
||||
} |
||||
|
||||
int pthread_setcanceltype(int type, int *oldtype) |
||||
{ |
||||
(void) type; |
||||
(void) oldtype; |
||||
return 0; |
||||
} |
||||
|
||||
void pthread_testcancel(void) |
||||
{ |
||||
pthread_t self = pthread_self(); |
||||
if (pthread_sched_threads[self]->should_cancel) { |
||||
pthread_exit(NULL); |
||||
} |
||||
} |
@ -0,0 +1,157 @@
|
||||
/**
|
||||
* POSIX implementation of threading. |
||||
* |
||||
* Copyright (C) 2013 Freie Universität Berlin |
||||
* |
||||
* This file subject to the terms and conditions of the GNU Lesser General |
||||
* Public License. See the file LICENSE in the top level directory for more |
||||
* details. |
||||
* |
||||
* @ingroup posix |
||||
* @{ |
||||
* @file pthread.c |
||||
* @brief Implementation of pthread. |
||||
* @author Christian Mehlis <mehlis@inf.fu-berlin.de> |
||||
* @author René Kijewski <kijewski@inf.fu-berlin.de> |
||||
* @} |
||||
*/ |
||||
|
||||
#include <string.h> |
||||
|
||||
#include "pthread.h" |
||||
|
||||
int pthread_attr_init(pthread_attr_t *attr) |
||||
{ |
||||
memset(attr, 0, sizeof (*attr)); |
||||
return 0; |
||||
} |
||||
|
||||
int pthread_attr_destroy(pthread_attr_t *attr) |
||||
{ |
||||
(void) attr; |
||||
return 0; |
||||
} |
||||
|
||||
int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate) |
||||
{ |
||||
*detachstate = attr->detached ? PTHREAD_CREATE_DETACHED : PTHREAD_CREATE_JOINABLE; |
||||
return 0; |
||||
} |
||||
|
||||
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate) |
||||
{ |
||||
switch (detachstate) { |
||||
case PTHREAD_CREATE_DETACHED: |
||||
attr->detached = 1; |
||||
return 0; |
||||
case PTHREAD_CREATE_JOINABLE: |
||||
attr->detached = 0; |
||||
return 0; |
||||
default: |
||||
return -1; |
||||
} |
||||
} |
||||
|
||||
int pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize) |
||||
{ |
||||
// TODO
|
||||
(void) attr; |
||||
(void) guardsize; |
||||
return -1; |
||||
} |
||||
|
||||
int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize) |
||||
{ |
||||
// TODO
|
||||
(void) attr; |
||||
(void) guardsize; |
||||
return -1; |
||||
} |
||||
|
||||
int pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *param) |
||||
{ |
||||
// TODO
|
||||
(void) attr; |
||||
(void) param; |
||||
return -1; |
||||
} |
||||
|
||||
int pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param) |
||||
{ |
||||
// TODO
|
||||
(void) attr; |
||||
(void) param; |
||||
return -1; |
||||
} |
||||
|
||||
int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy) |
||||
{ |
||||
// TODO
|
||||
(void) attr; |
||||
(void) policy; |
||||
return -1; |
||||
} |
||||
|
||||
int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy) |
||||
{ |
||||
// TODO
|
||||
(void) attr; |
||||
(void) policy; |
||||
return -1; |
||||
} |
||||
|
||||
int pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inherit) |
||||
{ |
||||
// TODO
|
||||
(void) attr; |
||||
(void) inherit; |
||||
return -1; |
||||
} |
||||
|
||||
int pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit) |
||||
{ |
||||
// TODO
|
||||
(void) attr; |
||||
(void) inherit; |
||||
return -1; |
||||
} |
||||
|
||||
int pthread_attr_getscope(const pthread_attr_t *attr, int *scope) |
||||
{ |
||||
// TODO
|
||||
(void) attr; |
||||
(void) scope; |
||||
return -1; |
||||
} |
||||
|
||||
int pthread_attr_setscope(pthread_attr_t *attr, int scope) |
||||
{ |
||||
// TODO
|
||||
(void) attr; |
||||
(void) scope; |
||||
return -1; |
||||
} |
||||
|
||||
int pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr) |
||||
{ |
||||
*stackaddr = attr->ss_sp; |
||||
return 0; |
||||
} |
||||
|
||||
int pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr) |
||||
{ |
||||
attr->ss_sp = (char *) stackaddr; |
||||
return 0; |
||||
} |
||||
|
||||
int pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize) |
||||
{ |
||||
*stacksize = attr->ss_size; |
||||
return 0; |
||||
} |
||||
|
||||
int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize) |
||||
{ |
||||
attr->ss_size = stacksize; |
||||
return 0; |
||||
} |
@ -0,0 +1,59 @@
|
||||
/**
|
||||
* POSIX implementation of threading. |
||||
* |
||||
* Copyright (C) 2013 Freie Universität Berlin |
||||
* |
||||
* This file subject to the terms and conditions of the GNU Lesser General |
||||
* Public License. See the file LICENSE in the top level directory for more |
||||
* details. |
||||
* |
||||
* @ingroup posix |
||||
* @{ |
||||
* @file pthread.c |
||||
* @brief Implementation of pthread. |
||||
* @author Christian Mehlis <mehlis@inf.fu-berlin.de> |
||||
* @author René Kijewski <kijewski@inf.fu-berlin.de> |
||||
* @} |
||||
*/ |
||||
|
||||
#include <string.h> |
||||
#include <stddef.h> |
||||
|
||||
#include "pthread.h" |
||||
|
||||
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr) |
||||
{ |
||||
(void) mutexattr; |
||||
|
||||
return mutex_init(mutex); |
||||
} |
||||
|
||||
int pthread_mutex_destroy(pthread_mutex_t *mutex) |
||||
{ |
||||
(void) mutex; |
||||
|
||||
return 1; |
||||
} |
||||
|
||||
int pthread_mutex_trylock(pthread_mutex_t *mutex) |
||||
{ |
||||
return mutex_trylock(mutex); |
||||
} |
||||
|
||||
int pthread_mutex_lock(pthread_mutex_t *mutex) |
||||
{ |
||||
return mutex_lock(mutex); |
||||
} |
||||
|
||||
int pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *abstime) |
||||
{ |
||||
(void) mutex; |
||||
(void) abstime; |
||||
return 0; /* currently not supported */ |
||||
} |
||||
|
||||
int pthread_mutex_unlock(pthread_mutex_t *mutex) |
||||
{ |
||||
mutex_unlock(mutex); |
||||
return 1; |
||||
} |
@ -0,0 +1,30 @@
|
||||
/**
|
||||
* POSIX implementation of threading. |
||||
* |
||||
* Copyright (C) 2013 Freie Universität Berlin |
||||
* |
||||
* This file subject to the terms and conditions of the GNU Lesser General |
||||
* Public License. See the file LICENSE in the top level directory for more |
||||
* details. |
||||
* |
||||
* @ingroup posix |
||||
* @{ |
||||
* @file pthread.c |
||||
* @brief Implementation of pthread. |
||||
* @author Christian Mehlis <mehlis@inf.fu-berlin.de> |
||||
* @author René Kijewski <kijewski@inf.fu-berlin.de> |
||||
* @} |
||||
*/ |
||||
|
||||
#include "pthread.h" |
||||
|
||||
int pthread_once(pthread_once_t *once_control, void (*init_routine)(void)) |
||||
{ |
||||
if (*once_control == PTHREAD_ONCE_INIT) { |
||||
init_routine(); |
||||
} |
||||
|
||||
*once_control = PTHREAD_ONCE_INIT + 1; |
||||
|
||||
return 0; |
||||
} |
@ -0,0 +1,55 @@
|
||||
/**
|
||||
* POSIX implementation of threading. |
||||
* |
||||
* Copyright (C) 2013 Freie Universität Berlin |
||||
* |
||||
* This file subject to the terms and conditions of the GNU Lesser General |
||||
* Public License. See the file LICENSE in the top level directory for more |
||||
* details. |
||||
* |
||||
* @ingroup posix |
||||
* @{ |
||||
* @file pthread.c |
||||
* @brief Implementation of pthread. |
||||
* @author Christian Mehlis <mehlis@inf.fu-berlin.de> |
||||
* @author René Kijewski <kijewski@inf.fu-berlin.de> |
||||
* @} |
||||
*/ |
||||
|
||||
#include "pthread.h" |
||||
|
||||
int pthread_spin_init(pthread_spinlock_t *lock, int pshared) |
||||
{ |
||||
(void) pshared; |
||||
*lock = 0; |
||||
return 0; |
||||
} |
||||
|
||||
int pthread_spin_destroy(pthread_spinlock_t *lock) |
||||
{ |
||||
(void) lock; |
||||
return 0; |
||||
} |
||||
|
||||
int pthread_spin_lock(pthread_spinlock_t *lock) |
||||
{ |
||||
while (*lock) { |
||||
; /* spin */ |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
int pthread_spin_trylock(pthread_spinlock_t *lock) |
||||
{ |
||||
if (*lock) { |
||||
return 0; |
||||
} |
||||
|
||||
return -1; |
||||
} |
||||
|
||||
int pthread_spin_unlock(pthread_spinlock_t *lock) |
||||
{ |
||||
--*lock; |
||||
return 0; |
||||
} |
@ -0,0 +1,22 @@
|
||||
# name of your project
|
||||
export PROJECT = test_pthread
|
||||
|
||||
# for easy switching of boards
|
||||
export BOARD ?= native
|
||||
|
||||
# this has to be the absolute path of the RIOT-base dir
|
||||
export RIOTBASE = $(CURDIR)/../..
|
||||
|
||||
## Modules to include.
|
||||
USEMODULE += posix
|
||||
USEMODULE += pthread
|
||||
|
||||
ifeq ($(BOARD),native) |
||||
CFLAGS += -isystem $(RIOTBASE)/sys/posix/pthread/include
|
||||
else |
||||
export INCLUDES += -I$(RIOTBASE)/sys/posix/pthread/include \
|
||||
-I$(RIOTBASE)/sys/posix/include
|
||||
endif |
||||
|
||||
include $(RIOTBASE)/Makefile.include |
||||
|
@ -0,0 +1,39 @@
|
||||
#include <stdio.h> |
||||
#include <inttypes.h> |
||||
|
||||
#include "pthread.h" |
||||
|
||||
void *run(void *parameter) { |
||||
size_t n = (size_t) parameter; |
||||
size_t factorial = 1; |
||||
|
||||
printf("pthread: parameter = %u\n", (unsigned int) n); |
||||
|
||||
if (n > 0) { |
||||
for (size_t i = 1; i <= n; i++) { |
||||
factorial *= i; |
||||
} |
||||
} |
||||
|
||||
printf("pthread: factorial = %u\n", (unsigned int) factorial); |
||||
pthread_exit((void *)factorial); |
||||
|
||||
return NULL; |
||||
} |
||||
|
||||
int main(void) { |
||||
pthread_t th_id; |
||||
pthread_attr_t th_attr; |
||||
|
||||
size_t arg = 6; |
||||
printf("main parameter = %u\n", (unsigned int) arg); |
||||
|
||||
pthread_attr_init(&th_attr); |
||||
pthread_create(&th_id, &th_attr, run, (void *) arg); |
||||
size_t res; |
||||
pthread_join(th_id, (void **) &res); |
||||
printf("main: factorial = %u\n", (unsigned int) res); |
||||
puts("main: finished"); |
||||
return 0; |
||||
} |
||||
|
Loading…
Reference in new issue