Skip to content

Commit

Permalink
newlib: Initial thread-safe implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
DipSwitch committed Dec 20, 2015
1 parent 1ac9a0d commit 3f53d58
Show file tree
Hide file tree
Showing 6 changed files with 162 additions and 0 deletions.
4 changes: 4 additions & 0 deletions Makefile.dep
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# pull dependencies from drivers
include $(RIOTBASE)/drivers/Makefile.dep

ifneq (,$(filter newlib_thread_safe,$(USEMODULE)))
USEMODULE += newlib
endif

ifneq (,$(filter libcoap,$(USEPKG)))
USEMODULE += posix_sockets
endif
Expand Down
3 changes: 3 additions & 0 deletions core/include/tcb.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ typedef struct tcb_t {
const char *name; /**< thread's name */
int stack_size; /**< thread's stack size */
#endif
#ifdef MODULE_NEWLIB_THREAD_SAFE
struct reent newlib_reent; /**< thread's re-entrent object */
#endif
} tcb_t;

#ifdef __cplusplus
Expand Down
4 changes: 4 additions & 0 deletions core/sched.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,10 @@ int sched_run(void)
sched_active_pid = next_thread->pid;
sched_active_thread = (volatile tcb_t *) next_thread;

#ifdef MODULE_NEWLIB_THREAD_SAFE
_impure_ptr = &(sched_active_thread->newlib_reent);
#endif

DEBUG("sched_run: done, changed sched_active_thread.\n");

return 1;
Expand Down
3 changes: 3 additions & 0 deletions sys/newlib/thread_safe/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
MODULE = newlib_thread_safe

include $(RIOTBASE)/Makefile.base
74 changes: 74 additions & 0 deletions sys/newlib/thread_safe/env_lock.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* Copyright (C) 2015 Engineering-Spirit
*
* This file is subject to the terms and conditions of the GNU Lesser General
* Public License v2.1. See the file LICENSE in the top level directory for more
* details.
*/

/**
* @ingroup sys_newlib
* @{
*
* @file
* @brief Newlib thread-safe env implementation
*
* @author Nick v. IJzendoorn <nijzendoorn@engineering-spirit.nl>
*
* @}
*/

#include <sys/reent.h>

#include <thread.h>
#include <mutex.h>

#if MODULE_NEWLIB_THREAD_SAFE
static volatile kernel_pid_t _env_owner = KERNEL_PID_UNDEF;
static atomic_int_t _env_lock_recursion;
static mutex_t _env_mutex;
#endif

/**
* @brief __env_lock needs to provide recursive mutex locking
*/
void __env_lock(struct _reent *_r)
{
/* TODO another way would be to avoid rescheduling other tasks */
#if MODULE_NEWLIB_THREAD_SAFE
switch (mutex_trylock(&_env_mutex))
{
case 0:
/* mutex is already locked */
if (_env_owner != thread_getpid()) {
/* we are not the owner, so we wait till it's released and
* fall-trough the case statement */
mutex_lock(&_env_mutex);
}

continue;

case 1:
/* mutex now locked by us */
atomic_inc(&_env_lock_recursion);
_env_owner = thread_getpid();
break;
}
#else
(void) _r;
#endif
}

void __env_unlock(struct _reent *_r)
{
#if MODULE_NEWLIB_THREAD_SAFE
if (atomic_dec(&_env_lock_recursion) == 1) {
/* we just released the last recursion lock call */

_env_owner = KERNEL_PID_UNDEF;
mutex_unlock(&_env_mutex);
}
#else
(void) _r;
#endif
}
74 changes: 74 additions & 0 deletions sys/newlib/thread_safe/malloc_lock.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* Copyright (C) 2015 Engineering-Spirit
*
* This file is subject to the terms and conditions of the GNU Lesser General
* Public License v2.1. See the file LICENSE in the top level directory for more
* details.
*/

/**
* @ingroup sys_newlib
* @{
*
* @file
* @brief Newlib thread-safe malloc implementation
*
* @author Nick v. IJzendoorn <nijzendoorn@engineering-spirit.nl>
*
* @}
*/

#include <sys/reent.h>

#include <thread.h>
#include <mutex.h>

#if MODULE_NEWLIB_THREAD_SAFE
static volatile kernel_pid_t _malloc_owner = KERNEL_PID_UNDEF;
static atomic_int_t _malloc_lock_recursion;
static mutex_t _malloc_mutex;
#endif

/**
* @brief __malloc_lock needs to provide recursive mutex locking
*/
void __malloc_lock(struct _reent *_r)
{
/* TODO another way would be to avoid rescheduling other tasks */
#if MODULE_NEWLIB_THREAD_SAFE
switch (mutex_trylock(&_malloc_mutex))
{
case 0:
/* mutex is already locked */
if (_malloc_owner != thread_getpid()) {
/* we are not the owner, so we wait till it's released and
* fall-trough the case statement */
mutex_lock(&_malloc_mutex);
}

continue;

case 1:
/* mutex now locked by us */
atomic_inc(&_malloc_lock_recursion);
_malloc_owner = thread_getpid();
break;
}
#else
(void) _r;
#endif
}

void __malloc_unlock(struct _reent *_r)
{
#if MODULE_NEWLIB_THREAD_SAFE
if (atomic_dec(&_malloc_lock_recursion) == 1) {
/* we just released the last recursion lock call */

_malloc_owner = KERNEL_PID_UNDEF;
mutex_unlock(&_malloc_mutex);
}
#else
(void) _r;
#endif
}

0 comments on commit 3f53d58

Please sign in to comment.