Files
atomthreads/ports/atomvm/atomvm.c
2012-11-18 11:29:32 +01:00

853 lines
25 KiB
C

/*
* 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.
*/
/**
* \file
* Atom Virtual Machine.
*
*
* This module implements the virtual machine.
*
*
* \b Functions contained in this module:\n
*
* \b Function prototypes used for controlling the atom virtual machine: \n
*
* \li atomvmCtrlCreate(): .
* \li atomvmCtrlRun(): .
* \li atomvmCtrlIntRequest(): .
* \li atomvmCtrlClose(): .
*
* \b Function prototypes for use by the atom virtual machine: \n
*
* \li atomvmInterruptMask(): .
* \li atomvmContextCreate(): .
* \li atomvmContextSwitch(): .
* \li atomvmContextDesrtroy(): .
* \li atomvmWriteThreadId(): .
* \li atomvmReadThreadId(): .
* \li atomvmInterruptWait(): .
* \li atomvmGetVmId(): .
*
* \b Function prototypes to be implemted in the atom virtual machine: \n
*
* \li __atomvmReset(): .
* \li __atomvmClose(): .
*
*/
#include "atomvm.h"
#include <string.h>
#include <windows.h>
#define CONTEXT_VM (CONTEXT_INTEGER | CONTEXT_CONTROL | CONTEXT_SEGMENTS)
/* 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 ;
/* ATOMVM_CALLBACK_CONTEXT_SWITCH 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_SWITCH_S {
ATOMVM_CALLBACK callback ;
/* Context the callback function will operate on */
volatile PATOMVM_CONTEXT p_old_context ;
volatile PATOMVM_CONTEXT p_new_context ;
} ATOMVM_CALLBACK_CONTEXT_SWITCH, *PATOMVM_CALLBACK_CONTEXT_SWITCH ;
/* ATOMVM_CALLBACK_INT_REQUEST is the parameter for a ATOMVM_CALLBACK_F call
that take as parameter a pointer to to the function that will be called in
an interrupt context */
typedef struct ATOMVM_CALLBACK_INT_REQUEST_S {
ATOMVM_CALLBACK callback ;
/* Function pointer the callback will call */
void (*isr) (void) ;
} ATOMVM_CALLBACK_INT_REQUEST, *PATOMVM_CALLBACK_INT_REQUEST ;
/* 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 interrupt_mask is
set for the context. Interrupts will only occur while
the interrupt_mask is zero. */
volatile uint32_t interrupt_mask ;
uint32_t thread_id ;
} ATOMVM_CONTEXT, *PATOMVM_CONTEXT ;
/* ATOMVM defines the state of an instance to an atomvm. It is created
by a call to atomvmCtrlCreate(). */
typedef struct ATOMVM_S {
uint32_t atomvm_id ;
/* 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 */
ATOMVM_CONTEXT atom_init_context ;
} ATOMVM, *PATOMVM ;
/* Global declarations */
volatile uint32_t g_atomvm_id = 0 ;
volatile DWORD g_atomvm_tls_idx ;
/* Forward declaration for the atom virtual machine thread */
static DWORD WINAPI vm_thread (LPVOID lpParameter) ;
/**
* \ingroup atomvm
* \b atomvmCtrlCreate
*
* This is an atomvm controll function used by a controlling thread.
*
* Initializes the virtual machine.
*
* @param[out] atomvm Handle to the virtual machine to create.
*
* @return Zero on failure.
*/
uint32_t
atomvmCtrlCreate (HATOMVM *atomvm)
{
PATOMVM patomvm = 0 ;
patomvm = (PATOMVM) malloc (sizeof(struct ATOMVM_S)) ;
if (patomvm) {
memset (patomvm, 0, sizeof(struct ATOMVM_S)) ;
patomvm->atomvm_id = InterlockedIncrement(&g_atomvm_id) - 1 ;
if (patomvm->atomvm_id == 0) {
g_atomvm_tls_idx = TlsAlloc () ;
}
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) ;
ATOMVM_ASSERT(patomvm->atomvm_call && patomvm->atomvm_int && patomvm->atomvm_int_complete &&
patomvm->atomvm_close, _T("ResumeThread failed")) ;
patomvm->vm_thread = CreateThread (NULL, 0, vm_thread, (void*)patomvm, CREATE_SUSPENDED, NULL) ;
ATOMVM_ASSERT(patomvm->vm_thread, _T("CreateThread failed")) ;
patomvm->atom_init_context.interrupt_mask = 1 ;
patomvm->current_context = &patomvm->atom_init_context ;
*atomvm = (HATOMVM)patomvm ;
}
return patomvm != 0 ;
}
/**
* \ingroup atomvm
* \b atomvmCtrlRun
*
* After a call to atomvmCtrlCreate 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 atomvmCtrlCreate.
* @param[in] flags not used.
*
* @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 service_call ;
#if defined DEBUG || defined _DEBUG
BOOL tls_res =
#endif
TlsSetValue (g_atomvm_tls_idx, (void*) atomvm) ;
ATOMVM_ASSERT(tls_res, _T("TlsSetValue failed")) ;
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) {
service_call = patomvm->service_call ;
while (!service_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. Set
_WIN32_WINNT < 0x0600 if you are running Windows XP */
FlushProcessWriteBuffers ();
#endif
InterlockedExchange (&service_call->result, service_call->callback (patomvm, service_call)) ;
InterlockedExchange (&service_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->interrupt_mask == 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. Set
_WIN32_WINNT < 0x0600 if you are running Windows XP */
FlushProcessWriteBuffers ();
#endif
if (patomvm->current_context->interrupt_mask == 0) {
patomvm->status_isr++ ;
patomvm->isr () ;
patomvm->status_isr-- ;
res = ResumeThread (patomvm->vm_thread) ;
ATOMVM_ASSERT(res == 1 , _T("ResumeThread failed")) ;
ResetEvent (patomvm->atomvm_int) ;
InterlockedExchange ((volatile uint32_t*)&patomvm->isr, 0) ;
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 ;
} else {
ATOMVM_ASSERT(res == 1 , _T("WaitForMultipleObjects failed")) ;
}
}
}
/**
* \ingroup atomvm
* \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 atomvmCtrlCreate.
*
* ToDo: more testing.
*
* @param[in] atomvm Handle to the virtual machine created by atomvmCtrlCreate.
*
* @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) ;
// TlsFree (g_atomvm_tls_idx) ;
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 thread is suspended during the callback.
*
* @param[in] patomvm Pointer to the virtual machine created by atomvmCtrlCreate.
* @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 getAtomvm
*
* Get the atomvm instance for the calling thread
*
* @return atomvm instance
*/
__inline PATOMVM
getAtomvm (void)
{
PATOMVM patomvm = (PATOMVM) TlsGetValue (g_atomvm_tls_idx) ;
ATOMVM_ASSERT(patomvm , _T("TlsGetValue failed")) ;
return patomvm ;
}
/**
* \ingroup atomvm
* \b atomvmInterruptMask
*
* This function is to be used by the atom virtual machine.
*
* This function will mask interrupts for the current atomvm context.
*
* @param[in] mask zero enables interrupts any other value masks interrupts.
*
* @return Interrupt mask before the function call.
*/
int32_t
atomvmInterruptMask (uint32_t mask)
{
PATOMVM patomvm = getAtomvm () ;
int32_t interrupts = 0;
if (patomvm->status_isr == 0) {
interrupts = InterlockedExchange (&patomvm->current_context->interrupt_mask, mask) ;
}
return interrupts ;
}
/**
* \ingroup atomvm
* \b atomvmCtrlIntRequest
*
* This is an atomvm controll function used by external threads
* 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 return immediately after the interrupt was scheduled.
* The call will block while a previously scheduled interrupt is in progress.
*
* @param[in] atomvm Handle to the virtual machine created by atomvmCtrlCreate.
* @param[in] isr The address of the interrupt service routine.
*
* @return None
*/
void
atomvmCtrlIntRequest (HATOMVM atomvm, void (*isr) (void))
{
PATOMVM patomvm = (PATOMVM) atomvm ;
WaitForSingleObject (patomvm->atomvm_int_complete, INFINITE) ;
while (InterlockedCompareExchange ((volatile uint32_t *)&patomvm->isr, (uint32_t)isr, 0) != 0) {
SwitchToThread() ;
}
SetEvent (patomvm->atomvm_int) ;
}
/**
* \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 atomvmCtrlCreate.
* @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) ;
}
/**
* \ingroup atomvm
* \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] interrupt_mask initial interrupt mask of the thread.
*
* @return Handle to the context of the thread created.
*/
HATOMVM_CONTEXT
atomvmContextCreate (uint32_t interrupt_mask)
{
uint32_t res ;
PATOMVM patomvm = getAtomvm () ;
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->interrupt_mask = interrupt_mask ;
new_context->thread_id = (uint32_t) -1 ;
res = invokeCallback (patomvm, callbackContextCreate, (PATOMVM_CALLBACK)&context_init) ;
if (res) {
return (HATOMVM_CONTEXT)new_context ;
} else {
free (new_context) ;
}
return 0 ;
}
/**
* \ingroup atomvm
* \b atomvmContextInit
*
* This function is to be used by the atom virtual machine.
*
* This function initialize a atomvm thread context that can be scheduled
* by atomvmContextSwitch.
*
* @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 of the thread.
* @param[in] arg argument passed on the stack as first parameter.
* @param[in] exit exit function to return to.
* @param[in] status status for exit function.
*
* @return Zero on failure, try to call GetLastError().
*/
uint32_t
atomvmContextInit (HATOMVM_CONTEXT context, uint32_t* stack, void (*entry)(uint32_t), uint32_t arg, void (*exit)(uint32_t))
{
uint32_t res = 0 ;
PATOMVM_CONTEXT new_context = (PATOMVM_CONTEXT)context ;
CONTEXT* pcontext = &new_context->context ;
*stack-- = arg;
*stack = (uint32_t)exit ;
pcontext->Ebp = (uint32_t)stack ;
pcontext->Esp = (uint32_t)stack ;
pcontext->Eip = (uint32_t)entry ;
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 atomvmCtrlCreate.
* @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 = 1 ;
uint32_t res2 ;
PATOMVM_CALLBACK_CONTEXT_SWITCH context_switch = (PATOMVM_CALLBACK_CONTEXT_SWITCH)callback ;
if (context_switch->p_old_context) {
res1 = GetThreadContext (patomvm->vm_thread, &context_switch->p_old_context->context) ;
ATOMVM_ASSERT(res1 , _T("GetThreadContext failed")) ;
}
patomvm->current_context = context_switch->p_new_context ;
res2 = SetThreadContext (patomvm->vm_thread, &context_switch->p_new_context->context) ;
ATOMVM_ASSERT(res2 , _T("SetThreadContext failed")) ;
return res1 & res2 ;
}
/**
* \ingroup atomvm
* \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] new_context The context to schedule.
*
* @return Zero on failure, try to call GetLastError().
*/
uint32_t
atomvmContextSwitch (HATOMVM_CONTEXT old_context, HATOMVM_CONTEXT new_context)
{
PATOMVM patomvm = getAtomvm () ;
ATOMVM_CALLBACK_CONTEXT_SWITCH context_switch ;
context_switch.p_old_context = (PATOMVM_CONTEXT) old_context ;
context_switch.p_new_context = (PATOMVM_CONTEXT) new_context ;
return invokeCallback (patomvm, callbackContextSwitch, (PATOMVM_CALLBACK)&context_switch) ;
}
/**
* \ingroup atomvm
* \b atomvmContextDesrtroy
*
* This function is to be used by the atom virtual machine.
*
* This functiondestroyes a atomvm context created by atomvmContextCreate.
*
* @param[in] context The context to destroy.
*
* @return None
*/
void
atomvmContextDesrtroy (HATOMVM_CONTEXT context)
{
PATOMVM patomvm = getAtomvm () ;
ATOMVM_ASSERT(patomvm->current_context != (PATOMVM_CONTEXT)context,
_T("atomvmContextDesrtroy failed")) ;
free((void*)context) ;
}
/**
* \ingroup atomvm
* \b atomvmWriteThreadId
*
* Write a thread ID.
*
* Write a thread ID for the current context.
*
* @param[in] thread_id thread_id.
*
* @return None
*/
void
atomvmWriteThreadId (uint32_t thread_id)
{
PATOMVM patomvm = getAtomvm () ;
patomvm->current_context->thread_id = thread_id ;
}
/**
* \ingroup atomvm
* \b atomvmReadThreadId
*
* Write a thread ID.
*
* Read a thread ID for the current context.
*
* @return thread_id
*/
uint32_t
atomvmReadThreadId (void)
{
PATOMVM patomvm = getAtomvm () ;
return patomvm->current_context->thread_id ;
}
/**
* \ingroup atomvm
* \b atomvmGetVmId
*
* Returns an identifier for the virtual machine. This is zero for the first
* virtual machine created with atomvmCtrlCreate(), 1 for the second and so on.
*
* @return The atom vm ID
*/
uint32_t
atomvmGetVmId (void)
{
PATOMVM patomvm = getAtomvm () ;
return patomvm->atomvm_id ;
}
/**
* \b callbackInterruptWait
*
* This function is invoked from the controll thread after a call to atomvmInterruptWait().
*
* The atom virtual machine is suspended while this function is called.
*
* @param[in] patomvm Pointer to the virtual machine created by atomvmCtrlCreate.
* @param[out] callback Callback parameter.
*
* @return Zero on failure, try to call GetLastError().
*/
uint32_t
callbackIntWait (PATOMVM patomvm, PATOMVM_CALLBACK callback)
{
WaitForSingleObject (patomvm->atomvm_int_complete, INFINITE) ;
return WaitForSingleObject (patomvm->atomvm_int, INFINITE) == WAIT_OBJECT_0 ;
}
/**
* \ingroup atomvm
* \b atomvmInterruptWait
*
* This function is to be used by the atom virtual machine.
*
* This function if for synchronization between multiple
* atom vms.
*
*
* @return void.
*/
void
atomvmIntWait (void)
{
PATOMVM patomvm = getAtomvm () ;
ATOMVM_CALLBACK callback ;
invokeCallback (patomvm, callbackIntWait, (PATOMVM_CALLBACK)&callback) ;
}
/**
* \b callbackIntRequest
*
* This function is invoked from the controll thread after a call to atomvmIntRequest().
*
* The atom virtual machine is suspended while this function is called.
*
* @param[in] patomvm Pointer to the virtual machine created by atomvmCtrlCreate.
* @param[in] callback Callback parameter.
*
* @return Zero on failure, try to call GetLastError().
*/
uint32_t
callbackIntRequest (PATOMVM patomvm, PATOMVM_CALLBACK callback)
{
PATOMVM_CALLBACK_INT_REQUEST int_request = (PATOMVM_CALLBACK_INT_REQUEST)callback ;
int_request->isr () ;
return 1 ;
}
/**
* \ingroup atomvm
* \b atomvmIntRequest
*
* This function is to be used by the atom virtual machine.
*
* @param[in] isr Function that will be called from the controll thread.
*
* @return void.
*/
void
atomvmIntRequest (void (*isr) (void))
{
PATOMVM patomvm = getAtomvm () ;
ATOMVM_CALLBACK_INT_REQUEST callback ;
callback.isr = isr ;
invokeCallback (patomvm, callbackIntRequest, (PATOMVM_CALLBACK)&callback) ;
}
/**
* \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)
{
BOOL res = TlsSetValue (g_atomvm_tls_idx, lpParameter) ;
ATOMVM_ASSERT(res, _T("TlsSetValue failed")) ;
__atomvmReset () ;
return 0 ;
}