📄 arch_c.c
字号:
/*
* Copyright (c) 2004-2005, Dennis Kuschel.
* 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. The name of the author may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
*
*/
/*
* This file is originally from the pico]OS realtime operating system
* (http://picoos.sourceforge.net).
*
* CVS-ID $Id: arch_c.c,v 1.9 2006/03/14 18:44:26 dkuschel Exp $
*/
/* Note on compiler:
*
* This port was successfully tested with MS Visual C++ 6.0 and MinGW
*/
#define NANOINTERNAL
#define _X86ARCH_C
#include <picoos.h>
#undef INFINITE
#undef E_FAIL
#undef errno
#ifdef memset
#undef memset
#endif
#ifdef memcpy
#undef memcpy
#endif
#include <windows.h>
#include <stdio.h>
#include <conio.h>
#ifndef GCC
#define HAVEMMLIB
#endif
#ifdef HAVEMMLIB
#include <mmsystem.h>
#endif
#if HZ > 100
#error HZ is not allowed to be greater than 100 !
#endif
/*---------------------------------------------------------------------------
* PARAMETERS
*-------------------------------------------------------------------------*/
#define MIN_STACKSIZE (64 * 1024)
/*---------------------------------------------------------------------------
* TYPEDEFS
*-------------------------------------------------------------------------*/
typedef enum {
task_mustcreate,
task_exist,
task_interrupted,
task_mustquit,
task_terminated
} TSTATE_t;
typedef struct TASKPRIV_s {
HANDLE suspendSema;
HANDLE ownTaskHandle;
DWORD ownTaskID;
volatile TSTATE_t state;
POSTASKFUNC_t firstfunc;
void* taskarg;
UINT_t stacksize;
int priority;
volatile int blockIntFlag;
} *TASKPRIV_t;
/*---------------------------------------------------------------------------
* GLOBAL VARIABLES
*-------------------------------------------------------------------------*/
static HANDLE timerEvent_g;
static HANDLE globalSyncSem_g;
static HANDLE windowsThreadSyncMutex_g;
static HANDLE idleTaskSuspendSem_g;
static HANDLE interruptWaitSem_g;
static volatile DWORD interruptTaskId_g;
static volatile DWORD intlevelCounter_g;
static volatile int cpuIdleFlag_g;
static volatile int taskLockCnt_g;
static volatile int blockInterrupt_g;
static volatile int interruptWaiting_g;
static volatile int interruptActive_g;
static volatile int interruptExecuting_g;
static volatile int idleTaskCreated_g;
static volatile int archInitialized_g = 0;
static volatile int barrierCtr_g = 0;
/*---------------------------------------------------------------------------
* FUNCTION PROTOTYPES
*-------------------------------------------------------------------------*/
/* exported functions */
void p_pos_initArch(void);
void p_pos_softContextSwitch(void);
void p_pos_intContextSwitch(void);
void p_pos_startFirstContext(void);
void p_pos_globalLock(int *flags);
void p_pos_globalUnlock(int flags);
void singleThreadEnter(void);
void singleThreadExit(void);
void callInterruptHandler( void (*handlerfunc)(void) );
/* local functions */
static DWORD WINAPI a_newThread(LPVOID param);
static void a_enterInterruptlevel(void);
static void a_exitInterruptlevel(void);
static void a_quitThisTask(TASKPRIV_t thistask);
static void a_createThisTask(TASKPRIV_t thistask);
static void a_timerTask(void);
static void a_initTimer(void);
static void a_initTask(POSTASK_t task, UINT_t stacksize,
POSTASKFUNC_t funcptr, void *funcarg);
static void do_assert(const char* file, int line);
static void barrier(void);
#if POSCFG_ENABLE_NANO
static void a_keyboardInput(void);
#endif
#ifdef HAVEMMLIB
static void CALLBACK a_timerCallback(UINT uTimerID, UINT uMsg,
DWORD dwUser, DWORD dw1, DWORD dw2);
#endif
/*---------------------------------------------------------------------------
* MACROS
*-------------------------------------------------------------------------*/
#define GETTASKPRIV(taskhandle) ((TASKPRIV_t)((taskhandle)->portmem))
#define assert(x) if (!(x)) do_assert(__FILE__, __LINE__)
#define SemaWait(s) assert(WaitForSingleObject(s,INFINITE)==WAIT_OBJECT_0)
#define SemaSignal(s) ReleaseSemaphore(s, 1, NULL)
#define MutexWait(m) assert(WaitForSingleObject(m,INFINITE)==WAIT_OBJECT_0)
#define MutexSignal(m) ReleaseMutex(m)
/*---------------------------------------------------------------------------
* SOME HELPER FUNCTIONS
*-------------------------------------------------------------------------*/
void p_pos_assert(const char* text, const char *file, int line)
{
fprintf(stderr, "\n\n-- ASSERTION FAILED:\n\n\"%s\"\n\nfile %s, line %i\n\n",
text, file, line);
for(;;) { SemaWait(globalSyncSem_g); }
}
static void do_assert(const char* file, int line)
{
TASKPRIV_t thistask = GETTASKPRIV(posCurrentTask_g);
TASKPRIV_t nexttask = GETTASKPRIV(posNextTask_g);
fprintf(stderr, "\n\nASSERTION FAILED: %s, line %i\n\n", file, line);
fprintf(stderr, "taskLockCnt_g = %i\n", taskLockCnt_g);
fprintf(stderr, "blockInterrupt_g = %i\n", blockInterrupt_g);
fprintf(stderr, "interruptWaiting_g = %i\n", interruptWaiting_g);
fprintf(stderr, "interruptActive_g = %i\n", interruptActive_g);
fprintf(stderr, "interruptExecuting_g = %i\n\n", interruptExecuting_g);
#ifdef POS_DEBUGHELP
fprintf(stderr, "thistask: name = %s\n", posCurrentTask_g->deb.name);
fprintf(stderr, "thistask: deb_state = %i\n", posCurrentTask_g->deb.state);
#else
fprintf(stderr, "thistask: handle = %08x\n", (unsigned int)posCurrentTask_g);
#endif
#if SYS_TASKSTATE != 0
fprintf(stderr, "thistask: pico_state = %i\n", posCurrentTask_g->state);
#endif
fprintf(stderr, "thistask: arch_state = %i\n", thistask->state);
fprintf(stderr, "thistask: blockIntFl = %i\n", thistask->blockIntFlag);
if (thistask != nexttask)
{
#ifdef POS_DEBUGHELP
fprintf(stderr, "\nnexttask: name = %s\n", posNextTask_g->deb.name);
fprintf(stderr, "nexttask: deb_state = %i\n", posNextTask_g->deb.state);
#else
fprintf(stderr, "\nnexttask: handle = %08x\n", (unsigned int)posNextTask_g);
#endif
#if SYS_TASKSTATE != 0
fprintf(stderr, "nexttask: pico_state = %i\n", posNextTask_g->state);
#endif
fprintf(stderr, "nexttask: arch_state = %i\n", nexttask->state);
fprintf(stderr, "nexttask: blockIntFl = %i\n", nexttask->blockIntFlag);
}
for(;;) { SemaWait(globalSyncSem_g); }
}
static void barrier(void)
{
barrierCtr_g++;
}
void singleThreadEnter(void)
{
TASKPRIV_t thistask;
DWORD curthread = GetCurrentThreadId();
int flags, i;
i = 1;
while (!posRunning_g)
{
Sleep(i);
i = i * 2;
if (i > 500) i = 500;
}
if (interruptTaskId_g == curthread)
return;
thistask = GETTASKPRIV(posCurrentTask_g);
if (thistask->ownTaskID == curthread)
{
p_pos_globalLock(&flags);
return;
}
a_enterInterruptlevel();
}
void singleThreadExit(void)
{
TASKPRIV_t thistask = GETTASKPRIV(posCurrentTask_g);
DWORD curthread = GetCurrentThreadId();
if (interruptTaskId_g == curthread)
return;
if (thistask->ownTaskID == curthread)
{
p_pos_globalUnlock(taskLockCnt_g - 1);
return;
}
a_exitInterruptlevel();
}
void callInterruptHandler( void (*handlerfunc)(void) )
{
DWORD curthread = GetCurrentThreadId();
int i;
if (handlerfunc == NULL)
return;
i = 1;
while (!posRunning_g)
{
Sleep(i);
i = i * 2;
if (i > 500) i = 500;
}
a_enterInterruptlevel();
/* remember that we are in interrupt context now */
interruptTaskId_g = curthread;
/* call the pico]OS interrupt handler */
c_pos_intEnter();
#if POSCFG_ENABLE_NANO
if (handlerfunc == c_pos_timerInterrupt)
a_keyboardInput(); /* do the keyboard interrupt */
#endif
(handlerfunc)();
c_pos_intExit();
/* wake idle task */
cpuIdleFlag_g = 0;
SemaSignal(idleTaskSuspendSem_g);
interruptTaskId_g = 0;
a_exitInterruptlevel();
}
static void a_enterInterruptlevel(void)
{
/* synchronize Windows threads */
MutexWait(windowsThreadSyncMutex_g);
intlevelCounter_g++;
/* wait here until it is allowed to run the pico]OS functions */
if (intlevelCounter_g == 1)
{
again:
interruptActive_g = 1;
barrier();
while ((blockInterrupt_g != 0) || (taskLockCnt_g != 0))
{
interruptWaiting_g = 1;
if (taskLockCnt_g == 0)
{
if (!interruptWaiting_g)
SemaWait(interruptWaitSem_g);
interruptWaiting_g = 0;
break;
}
interruptActive_g = 0;
SemaWait(interruptWaitSem_g);
interruptActive_g = 1;
}
/* assert(taskLockCnt_g == 0); */
SemaWait(globalSyncSem_g);
/* assert(taskLockCnt_g == 0); */
if (taskLockCnt_g != 0)
{
/* this is a fast hack to catch a seldom race condition
on Windows 9x machines */
SemaSignal(globalSyncSem_g);
fprintf(stderr, "WARNING: arch_c.c: race condition detected\n");
goto again;
}
interruptExecuting_g = 1;
assert(taskLockCnt_g == 0);
}
}
static void a_exitInterruptlevel(void)
{
/* end the interrupt handler / interrupt level */
if (intlevelCounter_g == 1)
{
interruptExecuting_g = 0;
interruptActive_g = 0;
SemaSignal(globalSyncSem_g);
}
/* allow other threads to get to interrupt level */
intlevelCounter_g--;
MutexSignal(windowsThreadSyncMutex_g);
}
#ifdef HAVEMMLIB
static void CALLBACK a_timerCallback(UINT uTimerID, UINT uMsg,
DWORD dwUser, DWORD dw1, DWORD dw2)
{
SemaSignal(timerEvent_g);
}
#endif
static void a_initTimer(void)
{
#ifdef HAVEMMLIB
TIMECAPS timecaps;
BOOL tok;
timerEvent_g = CreateSemaphore(NULL, 0, 2*HZ, NULL);
tok = (timerEvent_g != NULL);
if (tok)
tok = timeGetDevCaps(&timecaps, sizeof(timecaps)) == TIMERR_NOERROR;
if (tok)
tok = timeBeginPeriod(timecaps.wPeriodMin) == TIMERR_NOERROR;
if (tok)
{
if (timeSetEvent(1000 / HZ, 1000 / HZ,
(LPTIMECALLBACK) a_timerCallback,
0, TIME_PERIODIC) == 0)
{
timeEndPeriod(timecaps.wPeriodMin);
tok = FALSE;
}
}
if (!tok && (timerEvent_g != NULL))
{
CloseHandle(timerEvent_g);
timerEvent_g = NULL;
}
#endif
}
static DWORD WINAPI a_newThread(LPVOID param)
{
TASKPRIV_t thistask = (TASKPRIV_t) param;
thistask->ownTaskID = GetCurrentThreadId();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -