ARM port: Support newlib thread reentrancy with thread-specific struct _reent. Tested on qemu_integratorcp.

This commit is contained in:
Kelvin Lawson
2016-01-03 00:10:39 +00:00
parent da01dde1f9
commit 2c0965c4a9
4 changed files with 52 additions and 1 deletions

View File

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

View File

@@ -27,6 +27,10 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <string.h>
#include <sys/reent.h>
#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));
}

View File

@@ -36,6 +36,9 @@
/* Definition of NULL is available from stddef.h on this platform */
#include <stddef.h>
/* Reentrancy structure */
#include <sys/reent.h>
/* 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 */

View File

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