mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
pthread: initial add
This commit is contained in:
parent
361c259948
commit
e865022a31
@ -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
Normal file
7
sys/posix/pthread/Makefile
Normal file
@ -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
Normal file
99
sys/posix/pthread/include/pthread.h
Normal file
@ -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
Normal file
67
sys/posix/pthread/include/pthread_attr.h
Normal file
@ -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
Normal file
25
sys/posix/pthread/include/pthread_barrier.h
Normal file
@ -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
Normal file
51
sys/posix/pthread/include/pthread_cond.h
Normal file
@ -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
Normal file
81
sys/posix/pthread/include/pthread_mutex.h
Normal file
@ -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
Normal file
53
sys/posix/pthread/include/pthread_rwlock.h
Normal file
@ -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
Normal file
17
sys/posix/pthread/include/pthread_spin.h
Normal file
@ -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
Normal file
36
sys/posix/pthread/include/pthreadtypes.h
Normal file
@ -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
Normal file
282
sys/posix/pthread/pthread.c
Normal file
@ -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
Normal file
157
sys/posix/pthread/pthread_attr.c
Normal file
@ -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
Normal file
59
sys/posix/pthread/pthread_mutex.c
Normal file
@ -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
Normal file
30
sys/posix/pthread/pthread_once.c
Normal file
@ -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
Normal file
55
sys/posix/pthread/pthread_spin.c
Normal file
@ -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
Normal file
22
tests/test_pthread/Makefile
Normal file
@ -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
Normal file
39
tests/test_pthread/main.c
Normal file
@ -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
Block a user