diff --git a/ports/arm/atomport-asm.s b/ports/arm/atomport-asm.s index 7ec981c..4ff7f14 100644 --- a/ports/arm/atomport-asm.s +++ b/ports/arm/atomport-asm.s @@ -43,6 +43,10 @@ .extern __interrupt_dispatcher +/* When using newlib, reentrancy context needs to be updated on task switch */ +.extern _impure_ptr + + /**/ .equ USR_MODE, 0x10 .equ FIQ_MODE, 0x11 @@ -80,6 +84,10 @@ archContextSwitch: STMFD sp!, {r4 - r11, lr} /* Save registers */ + ADD r4, r1, #4 /* Add offset to get address of new_tcb_ptr->reent context (second TCB element) */ + LDR r5, = _impure_ptr /* Get address of _impure_ptr into r5 */ + STR r4, [r5] /* Store new_tcb_ptr->reent context in _impure_ptr */ + STR sp, [r0] /* Save old SP in old_tcb_ptr->sp_save_ptr (first TCB element) */ LDR r1, [r1] /* Load new SP from new_tcb_ptr->sp_save_ptr (first TCB element) */ MOV sp, r1 @@ -120,6 +128,11 @@ archContextSwitch: * void archFirstThreadRestore (ATOM_TCB *new_tcb_ptr) */ archFirstThreadRestore: + + ADD r4, r0, #4 /* Add offset to get address of new_tcb_ptr->reent context (second TCB element) */ + LDR r5, = _impure_ptr /* Get address of _impure_ptr into r5 */ + STR r4, [r5] /* Store new_tcb_ptr->reent context in _impure_ptr */ + LDR r0, [r0] /* Get SP (sp_save_ptr is conveniently first element of TCB) */ MOV sp, r0 /* Load new stack pointer */ LDMFD sp!, {r4 - r11, pc} /* Load new registers */ diff --git a/ports/arm/atomport.c b/ports/arm/atomport.c index 4c117da..56e2137 100644 --- a/ports/arm/atomport.c +++ b/ports/arm/atomport.c @@ -27,6 +27,10 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include +#include +#include + #include "atom.h" #include "atomport.h" @@ -68,6 +72,13 @@ static void thread_shell (void) /* Get the TCB of the thread being started */ curr_tcb = atomCurrentContext(); + /** + * Open a stdout file descriptor so that the thread has its own stdout. + * In theory threads could open stdout to different output drivers + * if syscalls.s supported different output write functions. + */ + stdout = fopen ("/debuguart", "w"); + /** * Enable interrupts - these will not be enabled when a thread * is first restored. @@ -80,6 +91,9 @@ static void thread_shell (void) curr_tcb->entry_point(curr_tcb->entry_param); } + /* Clean up after thread completion */ + _reclaim_reent (&(curr_tcb->port_priv.reent)); + /* Thread has run to completion: remove it from the ready list */ curr_tcb->suspended = TRUE; atomSched (FALSE); @@ -153,5 +167,10 @@ void archThreadContextInit (ATOM_TCB *tcb_ptr, void *stack_top, void (*entry_poi */ tcb_ptr->sp_save_ptr = stack_ptr; + /** + * At thread startup (and every time we switch back to a thread) + * we set the global reentrancy pointer to this thread's reent struct + */ + _REENT_INIT_PTR (&(tcb_ptr->port_priv.reent)); } diff --git a/ports/arm/atomport.h b/ports/arm/atomport.h index 1025b18..a228615 100644 --- a/ports/arm/atomport.h +++ b/ports/arm/atomport.h @@ -36,6 +36,9 @@ /* Definition of NULL is available from stddef.h on this platform */ #include +/* Reentrancy structure */ +#include + /* Required number of system ticks per second (normally 100 for 10ms tick) */ #define SYSTEM_TICKS_PER_SEC 100 @@ -83,6 +86,15 @@ extern void contextExitCritical (uint32_t posture) ; #define CRITICAL_START() __atom_critical = contextEnterCritical() #define CRITICAL_END() contextExitCritical(__atom_critical) +/** + * When using newlib, define port private field in atom_tcb to be a + * struct _reent. + */ +struct arm_port_priv { + struct _reent reent; +}; +#define THREAD_PORT_PRIV struct arm_port_priv port_priv + /* Uncomment to enable stack-checking */ /* #define ATOM_STACK_CHECKING */ diff --git a/ports/arm/syscalls.c b/ports/arm/syscalls.c index 5933531..d89ba02 100644 --- a/ports/arm/syscalls.c +++ b/ports/arm/syscalls.c @@ -123,10 +123,17 @@ int _lseek(int file, int ptr, int dir) * * Simple stub implementation with no file table. All parameters ignored. * + * We only support reading/writing to the UART, so we don't bother inspecting + * the filename to decide which underlying device to use, _read() and _write() + * only access the UART driver. + * + * This is currently only called once (each thread opens its own stdout when + * it starts executing). + * */ int _open(const char *name, int flags, int mode) { - return -1; + return 0; }