Browse Source

pthread: initial add

dev/timer
Christian Mehlis 9 years ago
parent
commit
e865022a31
  1. 3
      sys/Makefile
  2. 7
      sys/posix/pthread/Makefile
  3. 99
      sys/posix/pthread/include/pthread.h
  4. 67
      sys/posix/pthread/include/pthread_attr.h
  5. 25
      sys/posix/pthread/include/pthread_barrier.h
  6. 51
      sys/posix/pthread/include/pthread_cond.h
  7. 81
      sys/posix/pthread/include/pthread_mutex.h
  8. 53
      sys/posix/pthread/include/pthread_rwlock.h
  9. 17
      sys/posix/pthread/include/pthread_spin.h
  10. 36
      sys/posix/pthread/include/pthreadtypes.h
  11. 282
      sys/posix/pthread/pthread.c
  12. 157
      sys/posix/pthread/pthread_attr.c
  13. 59
      sys/posix/pthread/pthread_mutex.c
  14. 30
      sys/posix/pthread/pthread_once.c
  15. 55
      sys/posix/pthread/pthread_spin.c
  16. 22
      tests/test_pthread/Makefile
  17. 39
      tests/test_pthread/main.c

3
sys/Makefile

@ -21,6 +21,9 @@ endif
ifneq (,$(filter pnet,$(USEMODULE)))
DIRS += posix/pnet
endif
ifneq (,$(filter pthread,$(USEMODULE)))
DIRS += posix/pthread
endif
ifneq (,$(filter shell,$(USEMODULE)))
DIRS += shell
endif

7
sys/posix/pthread/Makefile

@ -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

99
sys/posix/pthread/include/pthread.h

@ -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 */

67
sys/posix/pthread/include/pthread_attr.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);

25
sys/posix/pthread/include/pthread_barrier.h

@ -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);

51
sys/posix/pthread/include/pthread_cond.h

@ -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);

81
sys/posix/pthread/include/pthread_mutex.h

@ -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);

53
sys/posix/pthread/include/pthread_rwlock.h

@ -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);

17
sys/posix/pthread/include/pthread_spin.h

@ -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);

36
sys/posix/pthread/include/pthreadtypes.h

@ -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_ */

282
sys/posix/pthread/pthread.c

@ -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);
}
}

157
sys/posix/pthread/pthread_attr.c

@ -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;
}

59
sys/posix/pthread/pthread_mutex.c

@ -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;
}

30
sys/posix/pthread/pthread_once.c

@ -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;
}

55
sys/posix/pthread/pthread_spin.c

@ -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;
}

22
tests/test_pthread/Makefile

@ -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

39
tests/test_pthread/main.c

@ -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…
Cancel
Save