Skip to content

Commit

Permalink
Merge branch 'reentrancy'
Browse files Browse the repository at this point in the history
  • Loading branch information
jeuneS2 committed Aug 25, 2014
2 parents b714a43 + de3eacd commit 6ba6b74
Show file tree
Hide file tree
Showing 7 changed files with 266 additions and 1 deletion.
2 changes: 1 addition & 1 deletion libgloss/patmos/Makefile.in
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ SIM_BSP = libpatmos.a
SIM_CRTS = crt0.o crtbegin.o crtend.o
SIM_OBJS = open.o close.o read.o write.o lseek.o link.o unlink.o fstat.o\
isatty.o getpid.o exec.o fork.o wait.o kill.o exit.o sbrk.o\
times.o ftruncate.o stat.o chown.o chmod.o
times.o ftruncate.o stat.o chown.o chmod.o lock.o
SIM_INSTALL = install-sim

# Host specific makefile fragment comes in here.
Expand Down
25 changes: 25 additions & 0 deletions libgloss/patmos/crt0.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
// (COPYING3.LIB). If not, see <http://www.gnu.org/licenses/>.

#include <stddef.h>
#include <stdlib.h>
#include <reent.h>

#include "patmos.h"

Expand Down Expand Up @@ -67,6 +69,11 @@ unsigned _loader_baseaddr[MAX_CORES];
/// _loader_off - the offset of the loading function (one per core)
unsigned _loader_off[MAX_CORES];

/// _reent_ptr - data structure for reentrant library calls
struct _reent *_reent_ptr [MAX_CORES];
/// __initreent - initialize reentrancy structure
void __initreent(void) __attribute__((noinline));

//******************************************************************************
/// _start - main entry function to all patmos executables.
/// Setup the stack frame, initialize data structures, invoke main, et cetera.
Expand Down Expand Up @@ -110,6 +117,10 @@ void _start()
// clear the BSS section
// memset(&__bss_start, 0, &_end - &__bss_start);

// ---------------------------------------------------------------------------
// initialize reentrancy structure
__initreent();

// ---------------------------------------------------------------------------
// call initializers
__init();
Expand Down Expand Up @@ -149,3 +160,17 @@ void __fini(void) {
(*i)();
}
}

/// __initreent - initialize reentrancy structure
void __initreent(void) {
const int id = *((_iodev_ptr_t)(&_cpuinfo_base+0x0));
_reent_ptr[id] = malloc(sizeof(struct _reent));
_REENT_INIT_PTR(_reent_ptr[id]);
}

/// __getreent - get reentrancy structure for current thread
struct _reent *__getreent(void)
{
const int id = *((_iodev_ptr_t)(&_cpuinfo_base+0x0));
return _reent_ptr[id];
}
132 changes: 132 additions & 0 deletions libgloss/patmos/lock.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
// Copyright 2014 Technical University of Denmark, DTU Compute.
//
// This file is part of the newlib C library for the Patmos processor.
//
// This file is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This code is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// (COPYING3.LIB). If not, see <http://www.gnu.org/licenses/>.

#include <string.h>
#include <sys/lock.h>

#include <machine/patmos.h>

/* This locking implementation uses Lamport's baker algorithm.
*
* Rationale: It is faster than Peterson's generalized algorithm for N
* threads. Lamport's "fast" algorithm would be much faster for
* uncontended locks, but is not starvation-free.
*
* Caveat: The "number" field in the locking structure may be
* unbounded if a lock is continuously acquired/released without ever
* being free.
*/

int __patmos_lock_init(_LOCK_T *lock) {
_UNCACHED _LOCK_T *ll = (_UNCACHED _LOCK_T *)lock;
for (unsigned i = 0; i < sizeof(ll->entering)/sizeof(ll->entering[0]); i++) {
ll->entering[i] = 0;
}
for (unsigned i = 0; i < sizeof(ll->number)/sizeof(ll->number[0]); i++) {
ll->number[i] = 0;
}
return 0;
}

int __patmos_lock_init_recursive(_LOCK_RECURSIVE_T *lock) {
__lock_init(lock->lock);
_UNCACHED _LOCK_RECURSIVE_T *ll = (_UNCACHED _LOCK_RECURSIVE_T *)lock;
ll->owner = -1;
ll->depth = 0;
return 0;
}

int __patmos_lock_close(_LOCK_T *lock) {
return 0;
}

int __patmos_lock_close_recursive(_LOCK_RECURSIVE_T *lock) {
__lock_close(lock->lock);
return 0;
}

static unsigned max(_UNCACHED _LOCK_T *ll) {
unsigned m = 0;
for (unsigned i = 0; i < sizeof(ll->number)/sizeof(ll->number[0]); i++) {
unsigned n = ll->number[i];
m = n > m ? n : m;
}
return m;
}

int __patmos_lock_acquire(_LOCK_T *lock) {
unsigned char id = get_cpuid();
_UNCACHED _LOCK_T *ll = (_UNCACHED _LOCK_T *)lock;

ll->entering[id] = 1;
unsigned n = 1 + max(ll);
ll->number[id] = n;
ll->entering[id] = 0;

for (unsigned j = 0; j < sizeof(ll->number)/sizeof(ll->number[0]); j++) {
while (ll->entering[j]) {
/* busy wait */
}
unsigned m = ll->number[j];
while ((m != 0) &&
((m < n) || ((m == n) && (j < id)))) {
/* busy wait, only update m */
m = ll->number[j];
}
}

// invalidate data cache to establish cache coherence
inval_dcache();

return 0;
}

int __patmos_lock_release(_LOCK_T *lock) {
unsigned char id = get_cpuid();
_UNCACHED _LOCK_T *ll = (_UNCACHED _LOCK_T *)lock;

ll->number[id] = 0; // exit section

return 0;
}

int __patmos_lock_acquire_recursive(_LOCK_RECURSIVE_T *lock) {
unsigned char id = get_cpuid();
_UNCACHED _LOCK_RECURSIVE_T *ll = (_UNCACHED _LOCK_RECURSIVE_T *)lock;

if (ll->owner != id || ll->depth == 0) {
__lock_acquire(lock->lock);
ll->owner = id;
}

ll->depth++;

return 0;
}

int __patmos_lock_release_recursive(_LOCK_RECURSIVE_T *lock) {
_UNCACHED _LOCK_RECURSIVE_T *ll = (_UNCACHED _LOCK_RECURSIVE_T *)lock;

ll->depth--;

if (ll->depth == 0) {
ll->owner = -1; // reset owner to invalid ID
__lock_release(lock->lock);
}

return 0;
}
1 change: 1 addition & 0 deletions newlib/configure.host
Original file line number Diff line number Diff line change
Expand Up @@ -699,6 +699,7 @@ case "${host}" in
newlib_cflags="${newlib_cflags} -D_NO_GETLOGIN -D_NO_GETPWENT -D_NO_GETUT -D_NO_GETPASS -D_NO_SIGSET -D_NO_WORDEXP -D_NO_POPEN -D_NO_GLOB -D_NO_EXECVE"
# We do not support directories, disable compiling stand-in functions
newlib_cflags="${newlib_cflags} -DHAVE_OPENDIR"
newlib_cflags="${newlib_cflags} -D_REENT_NOGLOBAL"
;;
powerpc*-*-eabialtivec*)
default_newlib_io_long_long="yes"
Expand Down
5 changes: 5 additions & 0 deletions newlib/libc/include/sys/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,11 @@
#endif
#endif

#if defined(__patmos__) && !defined(__rtems__)
/* we want the reentrancy structure to be returned by a function */
#define __DYNAMIC_REENT__
#endif

#ifdef __mn10200__
#define __SMALL_BITFIELDS
#endif
Expand Down
6 changes: 6 additions & 0 deletions newlib/libc/include/sys/reent.h
Original file line number Diff line number Diff line change
Expand Up @@ -816,7 +816,9 @@ struct _reent
#endif

extern struct _reent *_impure_ptr __ATTRIBUTE_IMPURE_PTR__;
#ifndef _REENT_NOGLOBAL
extern struct _reent *_CONST _global_impure_ptr __ATTRIBUTE_IMPURE_PTR__;
#endif

void _reclaim_reent _PARAMS ((struct _reent *));

Expand All @@ -835,7 +837,11 @@ void _reclaim_reent _PARAMS ((struct _reent *));

#endif /* !_REENT_ONLY */

#ifndef _REENT_NOGLOBAL
#define _GLOBAL_REENT _global_impure_ptr
#else
#define _GLOBAL_REENT _REENT
#endif

#ifdef __cplusplus
}
Expand Down
96 changes: 96 additions & 0 deletions newlib/libc/machine/patmos/sys/lock.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// Copyright 2014 Technical University of Denmark, DTU Compute.
//
// This file is part of the newlib C library for the Patmos processor.
//
// This file is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This code is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// (COPYING3.LIB). If not, see <http://www.gnu.org/licenses/>.

#ifndef __SYS_LOCK_H__
#define __SYS_LOCK_H__

#ifndef __rtems__

#ifndef MAX_CORES
#define MAX_CORES 64
#endif

/* Locking structure to match Lamport's bakery locks */
typedef struct {
volatile unsigned char entering [MAX_CORES];
volatile unsigned int number [MAX_CORES];
} _LOCK_T;

typedef struct {
_LOCK_T lock;
volatile unsigned char owner;
volatile unsigned int depth;
} _LOCK_RECURSIVE_T;


#define __EMPTY_LOCK { { 0 }, { 0 } }

#define __LOCK_INIT(class,lock) \
class _LOCK_T lock = __EMPTY_LOCK;
#define __LOCK_INIT_RECURSIVE(class,lock) \
class _LOCK_RECURSIVE_T lock = { __EMPTY_LOCK, -1, 0 };


#define __lock_init(lock) __patmos_lock_init(&(lock))
#define __lock_init_recursive(lock) __patmos_lock_init_recursive(&(lock))
#define __lock_close(lock) __patmos_lock_close(&(lock))
#define __lock_close_recursive(lock) __patmos_lock_close_recursive(&(lock))
#define __lock_acquire(lock) __patmos_lock_acquire(&(lock))
#define __lock_acquire_recursive(lock) __patmos_lock_acquire_recursive(&(lock))
#define __lock_try_acquire(lock) __patmos_lock_try_acquire(&(lock))
#define __lock_try_acquire_recursive(lock) __patmos_lock_try_acquire_recursive(&(lock))
#define __lock_release(lock) __patmos_lock_release(&(lock))
#define __lock_release_recursive(lock) __patmos_lock_release_recursive(&(lock))


extern int __patmos_lock_init(_LOCK_T *lock);
extern int __patmos_lock_init_recursive(_LOCK_RECURSIVE_T *lock);
extern int __patmos_lock_close(_LOCK_T *lock);
extern int __patmos_lock_close_recursive(_LOCK_RECURSIVE_T *lock);
extern int __patmos_lock_acquire(_LOCK_T *lock);
extern int __patmos_lock_acquire_recursive(_LOCK_RECURSIVE_T *lock);
extern int __patmos_lock_try_acquire(_LOCK_T *lock);
extern int __patmos_lock_try_acquire_recursive(_LOCK_RECURSIVE_T *lock);
extern int __patmos_lock_release(_LOCK_T *lock);
extern int __patmos_lock_release_recursive(_LOCK_RECURSIVE_T *lock);

#else /* __rtems__ */

/* TODO: these are just dummies, replace with actual RTEMS locking functions */

typedef int _LOCK_T;
typedef int _LOCK_RECURSIVE_T;

#include <_ansi.h>

#define __LOCK_INIT(class,lock) static int lock = 0;
#define __LOCK_INIT_RECURSIVE(class,lock) static int lock = 0;
#define __lock_init(lock) (_CAST_VOID 0)
#define __lock_init_recursive(lock) (_CAST_VOID 0)
#define __lock_close(lock) (_CAST_VOID 0)
#define __lock_close_recursive(lock) (_CAST_VOID 0)
#define __lock_acquire(lock) (_CAST_VOID 0)
#define __lock_acquire_recursive(lock) (_CAST_VOID 0)
#define __lock_try_acquire(lock) (_CAST_VOID 0)
#define __lock_try_acquire_recursive(lock) (_CAST_VOID 0)
#define __lock_release(lock) (_CAST_VOID 0)
#define __lock_release_recursive(lock) (_CAST_VOID 0)

#endif

#endif /* __SYS_LOCK_H__ */

0 comments on commit 6ba6b74

Please sign in to comment.