New, atomvm!

Added ATOM_TLS for TLS or other thread specific storage.
This commit is contained in:
Natie van Rooyen
2010-09-03 22:23:47 +02:00
parent 916dc11a0c
commit b9e7e9cc63
9 changed files with 1357 additions and 0 deletions

View File

@@ -66,6 +66,10 @@ typedef struct atom_tcb
uint32_t stack_size; /* Size of stack allocation in bytes */
#endif
#ifdef ATOM_TLS
ATOM_TLS
#endif
} ATOM_TCB;

39
ports/atomvm/README.txt Normal file
View File

@@ -0,0 +1,39 @@
---------------------------------------------------------------------------
Library: Atomvn
Author: Natie van Rooyen <natie@navaro.nl>
License: BSD Revised
---------------------------------------------------------------------------
Atomvm is a tiny virtual machine that can run on Windows inside an IDE with a
debugger like Microsoft Visual C++ Express. The primary purpose of this VM is
for the evaluation of Real Time Operating Systems (like atomthreads) and
the development and testing of modules for this Real Time Operating System
in a user friendly environment.
---------------------------------------------------------------------------
BUILDING THE SOURCE
To test this project, just add all the files from the “atomthreads/kernel”
directory and the “atomthreads/ports/atomvm” directory as well as the test
program “atomthreads/ports/atomvm/test/main.c” to your project. Add both the
before mentioned directories to the include paths of your project and compile.
Atomvm was designed for multi core systems but also runs well on single core
systems.
---------------------------------------------------------------------------
RUNNING THE TESTS
The test, main.c, was designed to stress the vm as opposed to testing the RTOS.
However, the test can also run the unit tests if desired by using the
precompiled directive UNIT_TESTS and linking in the desired unit test.
---------------------------------------------------------------------------
FINALLY
Good luck, but most of all, have fun!

View File

@@ -0,0 +1,58 @@
/*
* Copyright (c) 2010, Kelvin Lawson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __ATOM_PORT_TESTS_H
#define __ATOM_PORT_TESTS_H
/* Include Atomthreads kernel API */
#include "atom.h"
/* Prerequisite include for ATOMLOG() macro (via printf) */
#include <stdio.h>
/* Logger macro for viewing test results */
#define ATOMLOG printf
/*
* String location macro: for platforms which need to place strings in
* alternative locations, e.g. on avr-gcc strings can be placed in
* program space, saving SRAM. On most platforms this can expand to
* empty.
*/
#define _STR(x) x
/* Default thread stack size (in bytes) */
#define TEST_THREAD_STACK_SIZE 0x4000
/* Uncomment to enable logging of stack usage to UART */
/* #define TESTS_LOG_STACK_USAGE */
#endif /* __ATOM_PORT_TESTS_H */

172
ports/atomvm/atomport.c Normal file
View File

@@ -0,0 +1,172 @@
/*
* Copyright (c) 2010, Kelvin Lawson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "atom.h"
#include "atomport.h"
#include "atomvm.h"
/** Forward declarations */
static void thread_shell (void);
DWORD WINAPI cntrl_thread_proc (LPVOID lpParameter) ;
/* Global data */
HATOMVM the_atomvm ;
/* Local data */
static HANDLE cntrl_thread ;
/**
* \b atomvmRun
*
* Starts the atom vm. atomvmRun creates a thread from where the atomvmCtrlRun function
* will be called. atomvmCtrlRun never returns and this thread becomes the controll
* thread of the vm.
*
*/
void
atomvmRun ()
{
atomvmCtrlInit (&the_atomvm) ;
cntrl_thread = CreateThread (NULL, 0, cntrl_thread_proc, 0, CREATE_SUSPENDED, NULL) ;
ResumeThread (cntrl_thread) ;
}
DWORD WINAPI
cntrl_thread_proc (LPVOID lpParameter)
{
atomvmCtrlRun (the_atomvm, 0) ;
return 0 ;
}
/**
* \b thread_shell
*
* Documented in atomThreads.
*
*/
void
thread_shell (void)
{
ATOM_TCB *curr_tcb;
/* Get the TCB of the thread being started */
curr_tcb = atomCurrentContext();
/**
* Enable interrupts - these will not be enabled when a thread
* is first restored.
*/
// sei();
atomvmExitCritical (the_atomvm) ;
/* Call the thread entry point */
if (curr_tcb && curr_tcb->entry_point)
{
curr_tcb->entry_point(curr_tcb->entry_param);
}
/* Not reached - threads should never return from the entry point */
}
/**
* \b archThreadContextInit
*
* Documented in atomThreads.
*
*/
void
archThreadContextInit (ATOM_TCB *tcb_ptr, void *stack_top, void (*entry_point)(uint32_t), uint32_t entry_param)
{
tcb_ptr->sp_save_ptr = stack_top;
tcb_ptr->entry_param = entry_param ;
tcb_ptr->entry_point = entry_point ;
atomvmContextCreate (the_atomvm, &tcb_ptr->context, (unsigned int )stack_top, (unsigned int )thread_shell) ;
}
/**
* \b archFirstThreadRestore
*
* Documented in atomThreads.
*
*/
void
archFirstThreadRestore(ATOM_TCB * p_sp_new)
{
atomvmContextSwitch (the_atomvm, p_sp_new->context) ;
}
/**
* \b archContextSwitch
*
* Documented in atomThreads.
*
*/
void
archContextSwitch (ATOM_TCB * p_sp_old, ATOM_TCB * p_sp_new)
{
atomvmContextSwitch (the_atomvm, p_sp_new->context) ;
}
/**
* \b archTimerTickIrqHandler
*
* System timer tick interrupt handler.
*
*/
void archTimerTickIrqHandler ()
{
atomIntEnter();
/* Call the OS system tick handler */
atomTimerTick();
/* Call the interrupt exit routine */
atomIntExit(TRUE);
}
unsigned int
__enter_critical ()
{
return atomvmEnterCritical (the_atomvm) ;
}
void
__exit_critical (unsigned int isr)
{
atomvmExitCritical (the_atomvm) ;
}

74
ports/atomvm/atomport.h Normal file
View File

@@ -0,0 +1,74 @@
/*
* Copyright (c) 2010, Kelvin Lawson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __ATOM_PORT_H__
#define __ATOM_PORT_H__
#include "atomvm.h"
#define SYSTEM_MEMALIGN sizeof (unsigned int)
#define SYSTEM_TICKS_PER_SEC 100
typedef unsigned int uintptr_t ;
typedef int intptr_t ;
typedef unsigned int uint32_t ;
typedef unsigned short uint16_t ;
typedef unsigned char uint8_t ;
typedef int int32_t ;
typedef short int16_t ;
typedef char int8_t ;
/**
* Architecture-specific types.
* Most of these are available from stdint.h on this platform, which is
* included above.
*/
#define POINTER void *
/* Critical region protection */
extern unsigned int __enter_critical() ;
extern void __exit_critical(unsigned int) ;
#define CRITICAL_STORE unsigned int __atom
#define CRITICAL_START() __atom = __enter_critical()
#define CRITICAL_END() __exit_critical(__atom)
#define ATOM_TLS HATOMVM_CONTEXT context ;
/* Function prototypes */
extern void atomvmRun () ;
extern void archTimerTickIrqHandler () ;
/* The instance of the atomvm for this port */
extern HATOMVM the_atomvm ;
#endif /* __ATOM_PORT_H */

63
ports/atomvm/atomuser.h Normal file
View File

@@ -0,0 +1,63 @@
/*
* Copyright (c) 2010,Kelvin Lawson. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#if 1
#ifndef __ATOM_USER_H__
#define __ATOM_USER_H__
/* Portable uint8_t and friends not available from stdint.h on this platform */
#include <windows.h>
#define SYSTEM_MEMALIGN sizeof (unsigned int)
typedef unsigned int uintptr_t ;
typedef int intptr_t ;
typedef unsigned int uint32_t ;
typedef unsigned short uint16_t ;
typedef unsigned char uint8_t ;
typedef int int32_t ;
typedef short int16_t ;
typedef char int8_t ;
/**
* Architecture-specific types.
* Most of these are available from stdint.h on this platform, which is
* included above.
*/
#define POINTER void *
#define ATOM_TLS HATOMVM_CONTEXT context ;
#endif /* __ATOM_USER_H__ */
#endif

626
ports/atomvm/atomvm.c Normal file
View File

@@ -0,0 +1,626 @@
/*
* Copyright (c) 2010, Natie van Rooyen. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "atomvm.h"
#include <string.h>
#define CONTEXT_VM (CONTEXT_INTEGER | CONTEXT_CONTROL | CONTEXT_SEGMENTS)
#define ATOMVM_ATOMVM_PERF_COUNTER(patomvm, counter) (InterlockedIncrement(&patomvm->perf_counters.counter))
/* Data types */
/* Forward declarations */
typedef struct ATOMVM_S * PATOMVM ;
typedef struct ATOMVM_CALLBACK_S * PATOMVM_CALLBACK ;
typedef struct ATOMVM_CONTEXT_S * PATOMVM_CONTEXT ;
typedef uint32_t (*ATOMVM_CALLBACK_F) (PATOMVM, PATOMVM_CALLBACK) ;
typedef struct ATOMVM_CALLBACK_S {
/* Address of callback function */
volatile ATOMVM_CALLBACK_F callback ;
/* Synchronization lock, the virtual machine will be suspended during
the callback. Regular WIN32 synchronization methods cant be used
because SuspendThread() is used on the vm thread. */
volatile uint32_t lock ;
/* Result of the call */
volatile uint32_t result ;
} ATOMVM_CALLBACK, *PATOMVM_CALLBACK ;
/* ATOMVM_CALLBACK_CONTEXT is the parameter for a ATOMVM_CALLBACK_F call
that take as parameter a pointer to a ATOMVM_CONTEXT to operate on */
typedef struct ATOMVM_CALLBACK_CONTEXT_S {
ATOMVM_CALLBACK callback ;
/* Context the callback function will operate on */
volatile PATOMVM_CONTEXT pcontext ;
} ATOMVM_CALLBACK_CONTEXT, *PATOMVM_CALLBACK_CONTEXT ;
typedef struct ATOMVM_PERF_COUNTERS_S {
/* Number of interrupt requests */
uint32_t int_request ;
/* Number of service calls (context switches and
context init from atom virtual machime) */
uint32_t service_call ;
/* Total number of context switches */
uint32_t context_switch ;
} ATOMVM_PERF_COUNTERS, *PATOMVM_PERF_COUNTERS ;
/* ATOMVM_CONTEXT saves the state of a context created by
atomvmContextCreate() and sheduled by atomvmContextSwitch(). */
typedef struct ATOMVM_CONTEXT_S {
/* A virtual machine thread context. These are saved and restored
during context initialization and context switches */
CONTEXT context ;
/* When entering a critical section the critical_count is
incremented for the context. Interrupts will only occur while
the critical_count is zero. The functions atomvmExitCritical()
and atomvmEnterCritical() will respectively decrement and
increment the critical count */
volatile uint32_t critical_count ;
} ATOMVM_CONTEXT, *PATOMVM_CONTEXT ;
/* ATOMVM defines the state of an instance to an atomvm. It is created
by a call to atomvmCtrlInit(). */
typedef struct ATOMVM_S {
/* Thread the virtual machine will run in */
HANDLE vm_thread ;
/* Handles to events and mutexes used for synchronization */
HANDLE atomvm_call ;
HANDLE atomvm_int ;
HANDLE atomvm_int_complete ;
HANDLE atomvm_close ;
/* next ISR */
volatile void (*isr)(void) ;
/* True if in an ISR */
volatile uint32_t status_isr ;
/* The current context that was scheduled by a call
to atomvmContextSwitch() */
PATOMVM_CONTEXT current_context ;
/* Service call address, synchronization lock, parameters
and, return value for the current service call */
PATOMVM_CALLBACK service_call ;
/* Context for startup, before any context was scheduled
(workaround to not check everytime if the first context
was already started) */
ATOMVM_CONTEXT atom_init_context ;
/* Performance counters */
volatile ATOMVM_PERF_COUNTERS perf_counters ;
} ATOMVM, *PATOMVM ;
/* Forward declaration for the atom virtual machine thread */
static DWORD WINAPI vm_thread (LPVOID lpParameter) ;
/**
* \b atomvmCtrlInit
*
* This is an atomvm controll function used by a controlling thread
* and must not be called from the atom virtual machine.
*
* Initializes the virtual machine.
*
* ToDo: More Error checking.
*
* @param[out] atomvm Handle to the virtual machine created.
*
* @return Zero on failure.
*/
uint32_t
atomvmCtrlInit (HATOMVM *atomvm)
{
PATOMVM patomvm = (PATOMVM) malloc (sizeof(struct ATOMVM_S)) ;
if (patomvm) {
memset (patomvm, 0, sizeof(struct ATOMVM_S)) ;
patomvm->atomvm_call = CreateEvent (NULL, TRUE, FALSE, 0) ;
patomvm->atomvm_int = CreateEvent (NULL, TRUE, FALSE, 0) ;
patomvm->atomvm_int_complete = CreateEvent (NULL, FALSE, TRUE, 0) ;
patomvm->atomvm_close = CreateEvent (NULL, TRUE, FALSE, 0) ;
patomvm->vm_thread = CreateThread (NULL, 0, vm_thread, 0, CREATE_SUSPENDED, NULL) ;
patomvm->atom_init_context.critical_count = 1 ;
patomvm->current_context = &patomvm->atom_init_context ;
*atomvm = (HATOMVM)patomvm ;
}
return patomvm != 0 ;
}
/**
* \b atomvmCtrlRun
*
* This is an atomvm controll function used by a controlling thread
* and must not be called from the atom virtual machine.
*
* After a call to atomvmCtrlInit this function start the atom virtual machine.
* The calling thread will be used to manage interrupts and service calls in
* the virtual machine. This function will not return untill atomvmCtrlClose
* is called.
*
* @param[in] atomvm Handle to the virtual machine created by atomvmCtrlInit.
* @param[in] flags Reserved for later use.
*
* @return None
*/
void
atomvmCtrlRun (HATOMVM atomvm, uint32_t flags)
{
PATOMVM patomvm = (PATOMVM) atomvm ;
HANDLE wait[3] ;
uint32_t res ;
uint32_t wait_object ;
PATOMVM_CALLBACK pservice_call ;
ResumeThread (patomvm->vm_thread) ;
wait[0] = patomvm->atomvm_call ;
wait[1] = patomvm->atomvm_int ;
wait[2] = patomvm->atomvm_close ;
for(;;) {
wait_object = WaitForMultipleObjects (3, wait,FALSE,INFINITE) ;
if (wait_object == WAIT_OBJECT_0) {
ATOMVM_ATOMVM_PERF_COUNTER(patomvm, service_call) ;
//InterlockedExchange ((volatile uint32_t*)&pservice_call, (uint32_t)patomvm->service_call) ;
pservice_call = patomvm->service_call ;
while (!pservice_call->lock) {
SwitchToThread () ;
}
while ((res = SuspendThread (patomvm->vm_thread)) == (DWORD)-1) ;
ATOMVM_ASSERT(res == 0 , _T("SuspendThread failed")) ;
#if (_WIN32_WINNT >= 0x0600)
/*
This is used for multi processor machines to ensure the thread
is stopped before executing the next instruction. */
FlushProcessWriteBuffers ();
#endif
InterlockedExchange (&pservice_call->result, pservice_call->callback (patomvm, pservice_call)) ;
InterlockedExchange (&pservice_call->lock, 0) ;
ResetEvent (patomvm->atomvm_call) ;
res = ResumeThread (patomvm->vm_thread) ;
ATOMVM_ASSERT(res == 1 , _T("ResumeThread failed")) ;
}
else if (wait_object == WAIT_OBJECT_0 + 1) {
if (patomvm->current_context->critical_count == 0) {
while ((res = SuspendThread (patomvm->vm_thread)) == (DWORD)-1) ;
ATOMVM_ASSERT(res == 0 , _T("SuspendThread failed")) ;
#if (_WIN32_WINNT >= 0x0600)
/*
This is used for multi processor machines to ensure the thread
is stopped before executing the next instruction. */
FlushProcessWriteBuffers ();
#endif
if (patomvm->current_context->critical_count == 0) {
ATOMVM_ATOMVM_PERF_COUNTER(patomvm, int_request) ;
patomvm->status_isr++ ;
patomvm->isr () ;
patomvm->status_isr-- ;
res = ResumeThread (patomvm->vm_thread) ;
ATOMVM_ASSERT(res == 1 , _T("ResumeThread failed")) ;
InterlockedExchange ((volatile uint32_t*)&patomvm->isr, 0) ;
ResetEvent (patomvm->atomvm_int) ;
SetEvent (patomvm->atomvm_int_complete) ;
} else {
res = ResumeThread (patomvm->vm_thread) ;
ATOMVM_ASSERT(res == 1 , _T("ResumeThread failed")) ;
SwitchToThread () ;
}
} else {
SwitchToThread () ;
}
} else if (wait_object == WAIT_OBJECT_0 + 2) {
break ;
}
}
}
/**
* \b atomvmCtrlClose
*
* This is an atomvm controll function used by a controlling thread
* and must not be called from the atom virtual machine.
*
* Closes the virtual machine and release all memory and handles created
* in atomvmCtrlInit.
*
* ToDo: this function was never tested.
*
* @param[in] atomvm Handle to the virtual machine created by atomvmCtrlInit.
*
* @return None
*/
void
atomvmCtrlClose (HATOMVM atomvm)
{
PATOMVM patomvm = (PATOMVM) atomvm ;
DWORD code ;
__atomvmClose () ;
SetEvent (patomvm->atomvm_close) ;
do {
SwitchToThread () ;
GetExitCodeThread (patomvm->vm_thread, &code) ;
} while (code == STILL_ACTIVE) ;
CloseHandle (patomvm->atomvm_call) ;
CloseHandle (patomvm->atomvm_int) ;
CloseHandle (patomvm->atomvm_int_complete) ;
CloseHandle (patomvm->atomvm_close) ;
CloseHandle (patomvm->vm_thread) ;
free (atomvm) ;
}
/**
* \b invokeCallback
*
* Invokes callback functions in the context of the controll thread as
* requested from the virtual machine. In case this callback came from inside,
* an isr it is already in the conrtext of the controll thread and the callback
* routine is called directly.
*
* The atom virtual machine is suspended during the callback.
*
* @param[in] patomvm Pointer to the virtual machine created by atomvmCtrlInit.
* @param[in] callback Callback function.
* @param[in/out] context Context the function will operate on.
*
* @return Zero on failure, try to call GetLastError().
*/
uint32_t
invokeCallback (PATOMVM patomvm, ATOMVM_CALLBACK_F callback, PATOMVM_CALLBACK service_call)
{
uint32_t res ;
if (patomvm->status_isr == 0) {
service_call->lock = 0 ;
service_call->callback = callback ;
patomvm->service_call = service_call ;
SetEvent (patomvm->atomvm_call) ;
InterlockedIncrement (&service_call->lock) ;
while (service_call->lock != 0) ;
res = service_call->result ;
} else {
res = callback (patomvm, service_call) ;
}
return res ;
}
/**
* \b atomvmExitCritical
*
* This function is to be used by the atom virtual machine.
*
* This function will decrement the critical count for the current atomvm context.
* When the critical count reaches zero, interrupts will be enabled again. Calling
* this function from inside an isr has no effect.
*
* @param[in] atomvm Handle to the virtual machine created by atomvmCtrlInit.
*
* @return Critical count before this function was called.
*/
int32_t
atomvmExitCritical (HATOMVM atomvm)
{
PATOMVM patomvm = (PATOMVM) atomvm ;
int32_t count = 0;
if (patomvm->status_isr == 0) {
count = InterlockedDecrement (&patomvm->current_context->critical_count) ;
}
return count ;
}
/**
* \b atomvmEnterCritical
*
* This function is to be used by the atom virtual machine.
*
* This function will increment the critical count for the current atomvm
* context. Interrupts will be disabled when the critical count is not zero.
* Calling this function from inside an isr has no effect.
*
* All threads are created with a critical count of 1.
*
* @param[in] atomvm Handle to the virtual machine created by atomvmCtrlInit.
*
* @return Critical count before this function was called.
*/
int32_t
atomvmEnterCritical (HATOMVM atomvm)
{
PATOMVM patomvm = (PATOMVM) atomvm ;
int32_t count = 0 ;
if (patomvm->status_isr == 0) {
count = InterlockedIncrement (&patomvm->current_context->critical_count) ;
}
return count ;
}
/**
* \b atomvmCtrlIntRequest
*
* This is an atomvm controll function used by a controlling thread(s)
* and must not be called from the atom virtual machine.
*
* This function requests an interrupt service routine to be called in the
* context of the atom virtual machine.
*
* The call will block untill after the interrupt completes.
*
* @param[in] atomvm Handle to the virtual machine created by atomvmCtrlInit.
* @param[in] isr The address of the interrupt service routine. The routine must use
* the default calling convention of the compiler.
*
* @return None
*/
void
atomvmCtrlIntRequest (HATOMVM atomvm, uint32_t isr)
{
PATOMVM patomvm = (PATOMVM) atomvm ;
while (InterlockedCompareExchange ((volatile uint32_t *)&patomvm->isr, isr, 0) == 0) {
SwitchToThread() ;
}
SignalObjectAndWait(patomvm->atomvm_int, patomvm->atomvm_int_complete, INFINITE, FALSE) ;
}
/**
* \b callbackContextCreate
*
* This function is invoked from the controll thread after a call to atomvmContextCreate.
*
* The atom virtual machine is suspended while this function is called.
*
* @param[in] patomvm Pointer to the virtual machine created by atomvmCtrlInit.
* @param[out] context Context to be initialized.
*
* @return Zero on failure, try to call GetLastError().
*/
uint32_t
callbackContextCreate (PATOMVM patomvm, PATOMVM_CALLBACK callback)
{
PATOMVM_CALLBACK_CONTEXT context_switch = (PATOMVM_CALLBACK_CONTEXT)callback;
CONTEXT * pcontext = &context_switch->pcontext->context ;
pcontext->ContextFlags = CONTEXT_VM ;
return GetThreadContext (patomvm->vm_thread, pcontext) ;
}
/**
* \b atomvmContextCreate
*
* This function is to be used by the atom virtual machine.
*
* This function creates a atomvm thread context that can be scheduled
* by atomvmContextSwitch.
*
* @param[in] atomvm Handle to the virtual machine created by atomvmCtrlInit.
* @param[out] context Handle to the context of the thread that are allocated
* by the caller.
* @param[in] stack Stack top.
* @param[in] entry Entry point using the default caling convention of the compiler.
*
* @return Zero on failure, try to call GetLastError().
*/
uint32_t
atomvmContextCreate (HATOMVM atomvm, HATOMVM_CONTEXT* atomvm_context, uint32_t stack, uint32_t entry)
{
uint32_t res ;
PATOMVM patomvm = (PATOMVM) atomvm ;
PATOMVM_CONTEXT new_context = (PATOMVM_CONTEXT)malloc (sizeof(ATOMVM_CONTEXT)) ;
CONTEXT* pcontext = &new_context->context ;
ATOMVM_CALLBACK_CONTEXT context_init ;
context_init.pcontext = new_context ;
new_context->critical_count = 1 ;
res = invokeCallback (patomvm, callbackContextCreate, (PATOMVM_CALLBACK)&context_init) ;
if (res) {
pcontext->Ebp = stack ;
pcontext->Esp = stack ;
pcontext->Eip = entry ;
*atomvm_context = (HATOMVM_CONTEXT)new_context ;
}
return res ;
}
/**
* \b callbackContextSwitch
*
* This function is invoked from the controll thread after a call to atomvmContextSwitch.
*
* The atom virtual machine is suspended while this function is called.
*
* @param[in] patomvm Pointer to the virtual machine created by atomvmCtrlInit.
* @param[out] context Context to be scheduled.
*
* @return Zero on failure, try to call GetLastError().
*/
uint32_t
callbackContextSwitch (PATOMVM patomvm, PATOMVM_CALLBACK callback)
{
uint32_t res1 ;
uint32_t res2 ;
PATOMVM_CALLBACK_CONTEXT context_switch = (PATOMVM_CALLBACK_CONTEXT)callback ;
CONTEXT* pnew_context = &context_switch->pcontext->context ;
ATOMVM_ATOMVM_PERF_COUNTER(patomvm, context_switch) ;
res1 = GetThreadContext (patomvm->vm_thread, &patomvm->current_context->context) ;
ATOMVM_ASSERT(res1 , _T("GetThreadContext failed")) ;
InterlockedExchange ((volatile uint32_t*)&patomvm->current_context, (uint32_t)pnew_context) ;
res2 = SetThreadContext (patomvm->vm_thread, &patomvm->current_context->context) ;
ATOMVM_ASSERT(res2 , _T("SetThreadContext failed")) ;
return res1 & res2 ;
}
/**
* \b atomvmContextSwitch
*
* This function is to be used by the atom virtual machine.
*
* This function schedules a thread for the context created by atomvmContextCreate.
*
* @param[in] atomvm Handle to the virtual machine created by atomvmCtrlInit.
* @param[in] new_context The context to schedule.
*
* @return Zero on failure, try to call GetLastError().
*/
uint32_t
atomvmContextSwitch (HATOMVM atomvm, HATOMVM_CONTEXT new_context)
{
PATOMVM patomvm = (PATOMVM) atomvm ;
ATOMVM_CALLBACK_CONTEXT context_switch ;
context_switch.pcontext = (PATOMVM_CONTEXT) new_context ;
return invokeCallback (patomvm, callbackContextSwitch, (PATOMVM_CALLBACK)&context_switch) ;
}
/**
* \b atomvmContextDesrtroy
*
* This function is to be used by the atom virtual machine.
*
* This functiondestroyes a atomvm context created by atomvmContextCreate.
*
* @param[in] atomvm Handle to the virtual machine created by atomvmCtrlInit.
* @param[in] context The context to destroy.
*
* @return None
*/
void
atomvmContextDesrtroy (HATOMVM atomvm, HATOMVM_CONTEXT context)
{
PATOMVM patomvm = (PATOMVM) atomvm ;
ATOMVM_ASSERT(patomvm->current_context != (PATOMVM_CONTEXT)context,
_T("atomvmContextDesrtroy failed")) ;
free((void*)context) ;
}
/**
* \b vm_thread
*
* Windows thread in which the atom virtual machine will execute.
*
* __atomvmReset() runs the virtual machie and should only return after
* __atomvmClose() was called.
*
* @return None.
*/
DWORD WINAPI
vm_thread (LPVOID lpParameter)
{
__atomvmReset () ;
return 0 ;
}

72
ports/atomvm/atomvm.h Normal file
View File

@@ -0,0 +1,72 @@
/*
* Copyright (c) 2010, Natie van Rooyen. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. No personal names or organizations' names associated with the
* Atomthreads project may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __ATOMVM_H__
#define __ATOMVM_H__
#include <crtdbg.h>
#include "atomuser.h"
#ifdef _DEBUG
#define ATOMVM_ASSERT(x, msg) _ASSERT(x)
#else
#define ATOMVM_ASSERT(x, msg)
#endif
/* Forward declarations */
/* This is an opaque handle to an instance of an atomvm created
by a call to atomvmCtrlInit() */
typedef struct ATOMVM* HATOMVM ;
/* This is an opaque handle to an atomvm context created
by a call to atomvmContextCreate() */
typedef struct ATOMVM_CONTEXT* HATOMVM_CONTEXT ;
/* Function prototypes used for controlling the atom virtual machine */
extern uint32_t atomvmCtrlInit (HATOMVM* atomvm) ;
extern void atomvmCtrlRun (HATOMVM atomvm, uint32_t flags) ;
extern void atomvmCtrlIntRequest (HATOMVM atomvm, uintptr_t isr) ;
extern void atomvmCtrlClose (HATOMVM atomvm) ;
/* Function prototypes for use by the atom virtual machine */
extern int32_t atomvmExitCritical (HATOMVM atomvm) ;
extern int32_t atomvmEnterCritical (HATOMVM atomvm) ;
extern uint32_t atomvmContextCreate (HATOMVM atomvm, HATOMVM_CONTEXT* context, uint32_t stack, uint32_t entry) ;
extern uint32_t atomvmContextSwitch (HATOMVM atomvm, HATOMVM_CONTEXT new_context) ;
extern void atomvmContextDesrtroy (HATOMVM atomvm, HATOMVM_CONTEXT context) ;
/* Function prototypes to be implemted in the atom virtual machine */
extern void __atomvmReset (void) ;
extern void __atomvmClose (void) ;
#endif /* __ATOMVM_H__ */

249
ports/atomvm/test/main.c Normal file
View File

@@ -0,0 +1,249 @@
#include <stdio.h>
#include <windows.h>
#include "atom.h"
#include "atomvm.h"
#include "atomport.h"
// #define UNIT_TESTS
#ifdef UNIT_TESTS
extern uint32_t test_start (void) ;
#endif
#define TEST_THREADS 51
#define TEST_STACK_BYTE_SIZE 0x10000
#define IDLE_STACK_BYTE_SIZE 0x10000
#define MONITOR_STACK_BYTE_SIZE 0x10000
static unsigned char idle_stack[IDLE_STACK_BYTE_SIZE] ;
static unsigned char monitor_stack[MONITOR_STACK_BYTE_SIZE] ;
static unsigned char test_stack[TEST_THREADS+1][TEST_STACK_BYTE_SIZE] ;
static unsigned int test_counter[TEST_THREADS+1] = {0} ;
static unsigned int test2_counter = 0 ;
static unsigned int test3_counter = 0 ;
static unsigned int test_isr_count = 0 ;
static unsigned char test2_stack[TEST_STACK_BYTE_SIZE] ;
static unsigned char test3_stack[TEST_STACK_BYTE_SIZE] ;
static unsigned char test_idle_stack[TEST_STACK_BYTE_SIZE] ;
static uint8_t test_prio[60] = {
001,010,100,200,250, 200,200,200,200,200,
150,150,150,150,150, 250,250,250,250,250,
101,102,103,104,105, 202,204,206,208,210,
150,150,150,150,150, 250,250,250,250,250,
121,122,123,124,125, 061,063,065,067,061,
150,150,150,150,150, 250,250,250,250,250
};
static uint32_t test_interv[60] = {
001,001,001,001,001, 002,003,004,005,006,
015,015,015,015,015, 025,024,023,022,021,
905,005,005,005,805, 050,051,052,053,054,
015,015,015,015,015, 025,024,023,022,021,
030,030,030,030,030, 070,071,072,073,474,
005,006,007,007,001, 001,001,003,003,005
};
ATOM_TCB test_tcb[TEST_THREADS+1] ;
ATOM_TCB monitor_tcb ;
ATOM_TCB test2_tcb ;
ATOM_TCB test3_tcb ;
ATOM_TCB test_idle_tcb ;
DWORD WINAPI isr_thread_proc (LPVOID lpParameter) ;
static HANDLE isr_thread_1 ;
static HANDLE isr_thread_2 ;
static HANDLE isr_thread_3 ;
static HANDLE isr_thread_4 ;
void
monitor_thread (uint32_t parm)
{
CRITICAL_STORE;
int i ;
int c = 0 ;
ATOM_TCB *tcb ;
tcb = atomCurrentContext() ;
for (;;)
{
CRITICAL_START();
printf("Monitor # %04d (%08d)\n", c++, atomTimeGet()) ;
printf("-------------------------\n") ;
for (i=0; i<TEST_THREADS/3; i++) {
printf("Thr %.2d cnt %08d\t",i,test_counter[i]);
printf("Thr %.2d cnt %08d\t",i+TEST_THREADS/3,test_counter[i+TEST_THREADS/3]);
printf("Thr %.2d cnt %08d\n",i+TEST_THREADS*2/3,test_counter[i+TEST_THREADS*2/3]);
}
printf("\nIdle Threadd 1 Counter = %d\nIdle Theadrd 2 Counter = %d\nInterrupt Counter = %d",test2_counter,test3_counter,test_isr_count);
printf ("\n\n") ;
CRITICAL_END();
atomTimerDelay (300) ;
}
}
void
test_thread (uint32_t parm)
{
CRITICAL_STORE;
for (;;) {
atomTimerDelay (test_interv[parm]) ;
CRITICAL_START();
test_counter[parm]++ ;
CRITICAL_END();
}
}
void
test2_thread (uint32_t parm)
{
CRITICAL_STORE;
for (;;) {
CRITICAL_START();
test2_counter++ ;
CRITICAL_END();
}
}
void test3_thread(uint32_t parm)
{
CRITICAL_STORE;
for (;;) {
CRITICAL_START();
test3_counter++ ;
CRITICAL_END();
}
}
#ifdef UNIT_TESTS
void unit_test_thread(uint32_t parm)
{
unsigned int failures ;
failures = test_start () ;
printf ("test_start %d failures\n", failures) ;
while(1) {
atomTimerDelay (100);
}
}
#endif
void
__atomvmReset ()
{
unsigned int i ;
atomOSInit(&idle_stack[IDLE_STACK_BYTE_SIZE - sizeof(unsigned int)], IDLE_STACK_BYTE_SIZE - sizeof(unsigned int)) ;
#ifndef UNIT_TESTS
for (i=0; i< TEST_THREADS;i++) {
atomThreadCreate ((ATOM_TCB *)&test_tcb[i], test_prio[i], test_thread, i, &test_stack[i][TEST_STACK_BYTE_SIZE - sizeof(unsigned int)], TEST_STACK_BYTE_SIZE - sizeof(unsigned int));
}
atomThreadCreate ((ATOM_TCB *)&monitor_tcb, 50, monitor_thread, 0, &monitor_stack[(MONITOR_STACK_BYTE_SIZE) - sizeof(unsigned int)], MONITOR_STACK_BYTE_SIZE - sizeof(unsigned int));
atomThreadCreate ((ATOM_TCB *)&test2_tcb, 253, test2_thread, 0, &test2_stack[(TEST_STACK_BYTE_SIZE) - sizeof(unsigned int)], (TEST_STACK_BYTE_SIZE) - sizeof(unsigned int));
atomThreadCreate ((ATOM_TCB *)&test3_tcb, 253, test3_thread, 0, &test3_stack[(TEST_STACK_BYTE_SIZE) - sizeof(unsigned int)], (TEST_STACK_BYTE_SIZE) - sizeof(unsigned int));
#else
atomThreadCreate ((ATOM_TCB *)&test2_tcb, 16, unit_test_thread, 0, &test2_stack[(TEST_STACK_BYTE_SIZE) - sizeof(unsigned int)], (TEST_STACK_BYTE_SIZE) - sizeof(unsigned int));
#endif
atomOSStart() ;
}
void
__atomvmClose ()
{
}
void
test_isr ()
{
static int i = 0 ;
test_isr_count++ ;
if (i++==25) {
//Sleep(3) ;
i = 0;
}
}
DWORD WINAPI
isr_thread_proc (LPVOID lpParameter)
{
int i = 0 ;
int x ;
int y = rand() % 100 ;
while (1) {
atomvmCtrlIntRequest (the_atomvm, (uintptr_t)test_isr) ;
if (i++==y) {
x = rand() % 50 ;
Sleep (x) ;
y = rand() % 100 ;
i = 0 ;
}
}
return 0 ;
}
void
main ()
{
atomvmRun () ;
#ifndef UNIT_TESTS
isr_thread_1 = CreateThread (NULL, 0, isr_thread_proc, 0, CREATE_SUSPENDED, NULL) ;
isr_thread_2 = CreateThread (NULL, 0, isr_thread_proc, 0, CREATE_SUSPENDED, NULL) ;
isr_thread_3 = CreateThread (NULL, 0, isr_thread_proc, 0, CREATE_SUSPENDED, NULL) ;
isr_thread_4 = CreateThread (NULL, 0, isr_thread_proc, 0, CREATE_SUSPENDED, NULL) ;
ResumeThread (isr_thread_1) ;
ResumeThread (isr_thread_2) ;
ResumeThread (isr_thread_3) ;
ResumeThread (isr_thread_4) ;
#endif
while (1) {
Sleep(1) ;
atomvmCtrlIntRequest (the_atomvm, (uintptr_t)archTimerTickIrqHandler) ;
}
}