%selectfile NULL_FILE
%include "commonthreadlib.tlc"
%function FcnDeclareProfileDataStruct()
%openfile retBuf
typedef struct {
int numSamples;
int maxNumSamples;
double startTime[%<::CompiledModel.ConcurrentExecutionProfileNumSamples>];
double endTime[%<::CompiledModel.ConcurrentExecutionProfileNumSamples>];
int coreID[%<::CompiledModel.ConcurrentExecutionProfileNumSamples>];
} profileDataT;
%closefile retBuf
%return retBuf
%endfunction
%function FcnDeclareProfileDataVar(numPeriodicMappedEntities, numPeriodicTriggers)
%openfile retBuf
profileDataT profileData[%<numPeriodicMappedEntities>];
int counterSamples[%<numPeriodicTriggers>];
%closefile retBuf
%return retBuf
%endfunction
%function FcnGenerateProfilingFunctions(numPeriodicMappedEntities)
%openfile retBuf
double profileReadTimer(void) {
LARGE_INTEGER readTime;
CHECK_STATUS(QueryPerformanceCounter(&readTime) == %, "QueryPerformanceCounter");
return (double)(readTime.QuadPart);
}
void initializeNumSamplesForProfiling(void) {
int idx;
%<SLibDeploymentDeclareSampleTimeHitIndexArrayForProfiling()>
for (idx = 0; idx < %<numPeriodicMappedEntities>; idx++) {
profileData[idx].numSamples = 0;
profileData[idx].maxNumSamples = (%<::CompiledModel.ConcurrentExecutionProfileNumSamples> -1) / sthId[idx] + 1;
}
}
void profile_task_start(int taskId) {
if (profileData[taskId].numSamples < profileData[taskId].maxNumSamples) {
profileData[taskId].coreID[profileData[taskId].numSamples] = GetCurrentProcessorNumber();
profileData[taskId].startTime[profileData[taskId].numSamples] = profileReadTimer();
}
}
void profile_task_end(int taskId) {
if (profileData[taskId].numSamples < profileData[taskId].maxNumSamples) {
profileData[taskId].endTime[profileData[taskId].numSamples] = profileReadTimer();
profileData[taskId].numSamples++;
}
}
%<SLibDeploymentWriteProfilingDataToHtml(numPeriodicMappedEntities, TLC_TRUE)>
%closefile retBuf
%return retBuf
%endfunction
%function FcnGenerateUtilFunctionsAndGlobalVariables(numPeriodicTasks, ...
numAperiodicTasks, numPeriodicTriggers) void
%assign numPeriodicMappedEntities = SLibGetNumPeriodicMappedEntities()
%openfile tmpFcnBuf
#define CHECK_STATUS(status,fcn) if (status != 0) {fprintf(stderr, "Call to %s returned error status (%d)./n", (fcn),(status)); perror((fcn)); fflush(stderr); exit(EXIT_FAILURE);}
typedef struct {
HANDLE threadHandle;
unsigned threadID;
int_T index;
HANDLE startEvent;
HANDLE stopEvent;
LONG exitFlag;
} ThreadInfo;
%if SLibIsTaskProfilingOn()
%<FcnDeclareProfileDataStruct()>
%endif
%if (numPeriodicTasks > 0)
ThreadInfo periodicThread[%<numPeriodicTasks>];
%endif
ThreadInfo periodicTriggerThread[%<numPeriodicTriggers>];
%if (numAperiodicTasks > 0)
ThreadInfo aperiodicThread[%<numAperiodicTasks>];
%endif
int threadPriority[4] = { THREAD_PRIORITY_ABOVE_NORMAL,
THREAD_PRIORITY_NORMAL,
THREAD_PRIORITY_BELOW_NORMAL,
THREAD_PRIORITY_LOWEST };
HANDLE rtClock[%<numPeriodicTriggers>];
HANDLE quitEvent = NULL;
%if SLibIsTaskProfilingOn()
%<FcnDeclareProfileDataVar(numPeriodicMappedEntities, numPeriodicTriggers)>
%endif
BOOL OnCtrlHandler(DWORD ctrl)
{
SetEvent(quitEvent);
return %;
}
%if SLibIsTaskProfilingOn()
%<FcnGenerateProfilingFunctions(numPeriodicMappedEntities)>
%endif
%closefile tmpFcnBuf
%<SLibCacheCodeToFile("mainSrc_data_defn", tmpFcnBuf)>
%endfunction
%function FcnGeneratePeriodicTaskSchedulerFunction(ehIdx, nTasks, stopCheck) void
%openfile tmpFcnBuf
unsigned __stdcall %<LibGetTriggerName(ehIdx)>TaskScheduler(void *arg)
{
volatile boolean_T noErr;
DWORD waitResult;
HANDLE orTimer;
LARGE_INTEGER orDueTime;
HANDLE eventArray[2];
%assign numTasks = LibGetNumTriggerTasks(ehIdx)
%if (numTasks > 1)
%assign indexVar = "i"
int_T %<indexVar>;
%endif
%if ::MultiInstanceERTCode && !::UsingMalloc && !::GenerateClassInterface
%<::tSimStructType> *const %<::tSimStruct> = %<::tSimStructPtr>;
%endif
%assign initStr = ""
%assign initStr2 = ""
%assign initStr3 = ""
%assign comma = ""
%assign triggerBaseRate = LibGetTriggerBaseRate(ehIdx)
%foreach taskIdx = numTasks
%assign initStr = initStr +"%<comma>0"
%assign initStr2 = initStr2 +"%<comma>%<nTasks>"
%if (numTasks > 1) && (!RootSystemIsSingleRate)
%assign stIdx = LibGetTriggerTaskSampleTimeIndex(ehIdx, taskIdx)
%assign taskSampleTime = LibGetSampleTimePeriodAndOffset(stIdx, 0)
%assign nTaskTicks = SLibComputeNumTaskTicks(taskSampleTime, ...
triggerBaseRate)
%assign initStr3 = initStr3 + "%<comma>%<nTaskTicks>"
%endif
%assign nTasks = nTasks + 1
%assign comma = ","
%endforeach
%if (numTasks > 1) && (!RootSystemIsSingleRate)
int_T taskCounters[%<numTasks>] = {%<initStr>};
int_T taskTicks[%<numTasks>] = {%<initStr3>};
%endif
int_T taskId[%<numTasks>] = {%<initStr2>};
noErr = %<stopCheck>;
eventArray[0] = quitEvent;
eventArray[1] = rtClock[%<ehIdx>];
orTimer = CreateWaitableTimer(NULL, %, NULL);
orDueTime.QuadPart = (LONGLONG)(%<LibGetTriggerBaseRate(ehIdx)> * 1e7 * -1);
while (noErr)
{
/* Wait for the next event from the timer */
waitResult = WaitForMultipleObjects(2, eventArray, %, INFINITE);
if ((waitResult == WAIT_OBJECT_0) || (waitResult == WAIT_FAILED))
{
/* The quitEvent is set or the wait failed */
noErr = %;
continue;
}
CHECK_STATUS(SetWaitableTimer(orTimer, &orDueTime, 0, NULL, NULL, %) == %, "SetWaitableTimer");
%if (numTasks > 1)
for (i = 0; i < %<numTasks>; i++)
{
%if !RootSystemIsSingleRate
if (taskCounters[i] == 0)
{
%endif
waitResult = WaitForSingleObject(periodicThread[taskId[i]].stopEvent, 0);
if (waitResult == WAIT_TIMEOUT)
{
%assign msg = "Overrun - rate for periodic task %d too fast."
printf("%<msg>/n", taskId[i]);
WaitForSingleObject(periodicThread[taskId[i]].stopEvent, INFINITE);
}
%if !RootSystemIsSingleRate
}
%endif
}
%else
waitResult = WaitForSingleObject(periodicThread[taskId[0]].stopEvent, 0);
if (waitResult == WAIT_TIMEOUT)
{
%assign msg = "Overrun - rate for periodic task %d too fast."
printf("%<msg>/n", taskId[0]);
WaitForSingleObject(periodicThread[taskId[0]].stopEvent,INFINITE);
}
%endif
noErr = %<stopCheck>;
if (noErr)
{
%if SLibIsTaskProfilingOn()
counterSamples[%<ehIdx>]+=%<SLibGetNumClockTicksForTrigger(ehIdx)>;
%endif
%if (numTasks > 1)
for (i = 0; i <%<numTasks>; i++)
{
%if !RootSystemIsSingleRate
if (taskCounters[i] == 0)
{
%endif
SetEvent(periodicThread[taskId[i]].startEvent);
%if !RootSystemIsSingleRate
}
%endif
}
%else
SetEvent(periodicThread[taskId[0]].startEvent);
%endif
%if (numTasks > 1) && (!RootSystemIsSingleRate)
for (i = 0; i <%<numTasks>; i++) {
taskCounters[i]++;
if (taskCounters[i] > (taskTicks[i]-1)) {
taskCounters[i] = 0;
}
}
%endif
}
%if (numTasks > 1) && (!RootSystemIsSingleRate)
else
{
for (i = 0; i < %<numTasks>; i++)
{
if (taskCounters[i] != 0)
{
WaitForSingleObject(periodicThread[taskId[i]].stopEvent,INFINITE);
}
}
}
%endif
if (WaitForSingleObject(orTimer, 0) == WAIT_OBJECT_0)
{
%assign msg = "Overrun - periodic trigger %<ehIdx> base rate too fast."
printf("%<msg>/n");
}
} /* while */
%if (numTasks > 1)
for (i = 0; i < %<numTasks>; i++)
{
InterlockedIncrement(&periodicThread[taskId[i]].exitFlag);
SetEvent(periodicThread[taskId[i]].startEvent);
}
%else
InterlockedIncrement(&periodicThread[taskId[0]].exitFlag);
SetEvent(periodicThread[taskId[0]].startEvent);
%endif
_endthreadex(0);
return 0;
}
%closefile tmpFcnBuf
%<SLibCacheCodeToFile("mainSrc_fcn_defn",tmpFcnBuf)>
%endfunction
%function FcnGeneratePeriodicTriggerFunction(ehIdx, stopCheck)
%openfile retBuf
unsigned __stdcall %<LibGetTriggerName(ehIdx)>(void *arg)
{
volatile boolean_T noErr;
DWORD waitResult;
HANDLE orTimer;
LARGE_INTEGER orDueTime;
HANDLE eventArray[2];
%if SLibIsTaskProfilingOn()
ThreadInfo* info = (ThreadInfo*)arg;
%else
/* Unused arguments */
(void)(arg);
%endif
noErr = %<stopCheck>;
eventArray[0] = quitEvent;
eventArray[1] = rtClock[%<ehIdx>];
orTimer = CreateWaitableTimer(NULL, %, NULL);
orDueTime.QuadPart = (LONGLONG)(%<LibGetTriggerBaseRate(ehIdx)> * 1e7 * -1);
while (noErr)
{
/* Wait for the next event from the timer */
waitResult = WaitForMultipleObjects(2, eventArray, %, INFINITE);
if ((waitResult == WAIT_OBJECT_0) || (waitResult == WAIT_FAILED))
{
/* The quitEvent is set or the wait failed */
noErr = %;
continue;
}
CHECK_STATUS(SetWaitableTimer(orTimer, &orDueTime, 0, NULL, NULL, %) == %, "SetWaitableTimer");
noErr = %<stopCheck>;
if (noErr)
{
%if SLibIsTaskProfilingOn()
counterSamples[%<ehIdx>]+=%<SLibGetNumClockTicksForTrigger(ehIdx)>;
%endif
%if SLibIsTaskProfilingOn()
profile_task_start(info->index);
%endif
%<LibCallTriggerISR(ehIdx)>
%if SLibIsTaskProfilingOn()
profile_task_end(info->index);
%endif
}
} /* while */
_endthreadex(0);
return 0;
}
%closefile retBuf
%return retBuf
%endfunction
%function FcnGeneratePeriodicTaskWrapperFunctions(numPeriodicTasks, numPeriodicTriggers) void
%assign stopCheck = "(%<RTMGetErrStat()> == %<SLibGetNullDefinitionFromTfl()>)"
%if RTMStopReqAccessed()
%assign stopCheck = stopCheck + " && !%<RTMGetStopRequested()>"
%endif
%openfile tmpFcnBuf
%if (numPeriodicTasks > 0)
unsigned __stdcall periodicTask(void *arg)
{
DWORD waitResult;
ThreadInfo* info = (ThreadInfo*)arg;
volatile boolean_T noErr = %;
%if ::MultiInstanceERTCode && !::UsingMalloc && !::GenerateClassInterface
%<::tSimStructType> *const %<::tSimStruct> = %<::tSimStructPtr>;
%endif
while (noErr)
{
waitResult = WaitForSingleObject(info->startEvent,INFINITE);
if ((waitResult != WAIT_OBJECT_0) || info->exitFlag)
{
/* Wait failed or exitFlag is set */
noErr = %;
continue;
}
%if SLibIsTaskProfilingOn()
profile_task_start(info->index);
%endif
%if ::GenerateClassInterface && SLibNeedWrapperStepFcn()!=0
%if ISEMPTY(::NamespaceName)
%<SLibModelStepFcnName("")>(%<::CPPObjectName>, %<GetErtModelFcnArgs("Output",TLC_TRUE,"info->index")>);
%else
%<::NamespaceName>::%<SLibModelStepFcnName("")>(%<::CPPObjectName>, %<GetErtModelFcnArgs("Output",TLC_TRUE,"info->index")>);
%endif
%else
%<LibCallModelStep("info->index")>
%endif
%if SLibIsTaskProfilingOn()
profile_task_end(info->index);
%endif
SetEvent(info->stopEvent);
}
_endthreadex(0);
return 0;
}
%endif
%assign taskCounter = 0
%foreach ehIdx = LibGetNumTriggers()
%assign evType = LibGetTriggerType(ehIdx)
%if ISEQUAL(evType, "AperiodicTrigger")
%continue
%endif
%if SLibIsTaskProfilingOn()
%assign finalStopCheck = stopCheck + " && (counterSamples[%<ehIdx>] < %<::CompiledModel.ConcurrentExecutionProfileNumSamples>)"
%else
%assign finalStopCheck = stopCheck
%endif
%if !ISEQUAL(LibGetNumTriggerTasks(ehIdx), 0)
%<FcnGeneratePeriodicTaskSchedulerFunction(ehIdx, taskCounter, ...
finalStopCheck)>
%assign taskCounter = taskCounter + LibGetNumTriggerTasks(ehIdx)
%else
%assert ISEQUAL(LibGetTriggerHandlerType(ehIdx), "isr")
%<FcnGeneratePeriodicTriggerFunction(ehIdx, finalStopCheck)>
%endif
%endforeach
%closefile tmpFcnBuf
%<SLibCacheCodeToFile("mainSrc_fcn_defn",tmpFcnBuf)>
%endfunction
%function FcnGenerateAperiodicWrapperFunctions() void
%openfile tmpFcnBuf
%foreach aehIdx = LibGetNumTriggers()
%assign evType = LibGetTriggerType(aehIdx)
%if ISEQUAL(evType, "PeriodicTrigger")
%continue
%endif
%assign targetObj = LibGetTriggerTargetObject(aehIdx)
%assign aehName = LibGetTriggerName(aehIdx)
%assign type = LibGetTriggerHandlerType(aehIdx)
%assert ISEQUAL(type, "task") || ISEQUAL(type, "isr")
%if ISEQUAL(type, "task")
%foreach taskIdx = LibGetNumTriggerTasks(aehIdx)
unsigned __stdcall %<aehName>_%<taskIdx>(void *arg)
{
DWORD waitResult;
HANDLE eventArray[2];
ThreadInfo* info = (ThreadInfo*)arg;
volatile boolean_T noErr = %;
eventArray[0] = quitEvent;
eventArray[1] = info->startEvent;
while (noErr)
{
waitResult = WaitForMultipleObjects(2, eventArray, %, INFINITE);
if ((waitResult == WAIT_FAILED) || (waitResult == WAIT_OBJECT_0))
{
noErr = %;
continue;
}
%<LibCallTriggerTask(aehIdx, taskIdx)>
}
_endthreadex(0);
return 0;
}
%endforeach
%else
%assign isrFuncName = "eventHandler_%<aehName>"
/* Software Interrupt */
unsigned __stdcall %<isrFuncName>(void *arg)
{
DWORD waitResult;
HANDLE eventArray[2];
ThreadInfo* info = (ThreadInfo*)arg;
volatile boolean_T noErr = %;
eventArray[0] = quitEvent;
eventArray[1] = info->startEvent;
while (noErr)
{
waitResult = WaitForMultipleObjects(2, eventArray, %, INFINITE);
if ((waitResult == WAIT_FAILED) || (waitResult == WAIT_OBJECT_0))
{
noErr = %;
continue;
}
%<LibCallTriggerISR(aehIdx)>
}
_endthreadex(0);
return 0;
}
%endif
%endforeach
%closefile tmpFcnBuf
%<SLibCacheCodeToFile("mainSrc_fcn_defn",tmpFcnBuf)>
%endfunction
%function FcnDeclareTaskPriorities(numAperiodicTasks, coreAffinityRequired)
%assign asyncPr = 0
%if (numAperiodicTasks > 0)
%assign asyncPr = 1
%endif
%openfile tmpBuf
%assign stIdRMSTaskWithLowPrio = -1
%assign isCorrectRMS = TLC_TRUE
%assign idx = 0
%if coreAffinityRequired
%assign maxNumberOfCoresPerTask = SLibGetMaxNumberOfCoresPerTask()
%assert maxNumberOfCoresPerTask > 0
%endif
%foreach ehIdx = LibGetNumTriggers()
%assign evType = LibGetTriggerType(ehIdx)
%if ISEQUAL(evType, "AperiodicTrigger")
%continue
%endif
%foreach taskIdx = LibGetNumTriggerTasks(ehIdx)
%assign stId = LibGetTriggerTaskSampleTimeIndex(ehIdx, taskIdx) + asyncPr
%assign stId = stId - LibGetTID01EQ()
%if (stId < 3)
priority[%<idx>] = threadPriority[%<stId>];
%else
%if SLibIsTaskRateMonotonic(ehIdx, taskIdx)
%if ISEQUAL(stIdRMSTaskWithLowPrio, -1)
%assign stIdRMSTaskWithLowPrio = stId
%elseif !ISEQUAL(stIdRMSTaskWithLowPrio, stId)
%assign isCorrectRMS = TLC_FALSE
%endif
%endif
priority[%<idx>] = threadPriority[3];
%endif
%if coreAffinityRequired
%assign affinity = LibGetTaskCoreAffinity(ehIdx, taskIdx)
%foreach index = maxNumberOfCoresPerTask
%if ISEMPTY(affinity) || SIZE(affinity,1)-1 < index
coreAffinity[%<idx>][%<index>] = -1;
%else
coreAffinity[%<idx>][%<index>] = %;
%endif
%endforeach
%endif
%assign idx = idx + 1
%endforeach
%endforeach
%if !isCorrectRMS
printf("There is a risk in running the generated code correctly because /n");
printf("the number of tasks with different periods that require rate monotonic /n");
printf("scheduling is larger than three. Consider reducing the number of rate /n");
printf("monotonic tasks in the model.");
fflush(stdout);
%endif
%closefile tmpBuf
%return tmpBuf
%endfunction
%function FcnGenerateMainFunction(numPeriodicTasks, numAperiodicTasks, ...
numPeriodicTriggers) void
%assign coreAffinityRequired = LibIsCoreAffinityRequired()
%openfile tmpFcnBuf
int main(int argc, char *argv[])
{
%if coreAffinityRequired
int i, j;
%else
int i;
%endif
LARGE_INTEGER stNanoSec;
LONG stMilliPeriod;
%if (numPeriodicTasks > 0)
%if coreAffinityRequired
SYSTEM_INFO sysinfo;
DWORD_PTR processMask;
DWORD_PTR systemMask;
DWORD_PTR threadMask;
%assign maxNumberOfCoresPerTask = SLibGetMaxNumberOfCoresPerTask()
%assert maxNumberOfCoresPerTask > 0
int coreAffinity[%<numPeriodicTasks>][%<maxNumberOfCoresPerTask>];
int numCores;
%endif
int priority[%<numPeriodicTasks>];
%endif
%if ::MultiInstanceERTCode && !::UsingMalloc && !::GenerateClassInterface
%<::tSimStructType> *const %<::tSimStruct> = %<::tSimStructPtr>;
%endif
/* Unused arguments */
(void)(argc);
(void)(argv);
%<FcnDeclareTaskPriorities(numAperiodicTasks, coreAffinityRequired)>
CHECK_STATUS(SetConsoleCtrlHandler((PHANDLER_ROUTINE)OnCtrlHandler, %) == %, "SetConsoleCtrlHandler");
for (i = 0; i < %<numPeriodicTriggers>; i++) {
rtClock[i] = NULL;
}
%if SLibIsTaskProfilingOn()
for (i = 0 ; i < %<numPeriodicTriggers>; i++) {
counterSamples[i] = 0;
}
initializeNumSamplesForProfiling();
%endif
printf("**starting the model**/n");
fflush(stdout);
%if ::UsingMalloc
%<FcnGenerateModelRegistration()>
if (%<::tSimStruct> == NULL) {
(void)fprintf(stderr,"Memory allocation error during model "
"registration");
return(EXIT_FAILURE);
}
%endif
%if ::MultiInstanceERTCode && !::UsingMalloc && !::GenerateClassInterface
%<FcnPackModelDataIntoRTM()>
%endif
%<FcnGenerateModelInitialize()>
%if !SuppressErrorStatus
%<RTMSetErrStat(0)>;
%endif
/* Set the priority of the main thread */
CHECK_STATUS(SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_TIME_CRITICAL) == %, "SetThreadPriority");
/* Create & initialize events used for thread synchronization */
quitEvent = CreateEvent(NULL, %, %, NULL);
CHECK_STATUS(quitEvent == NULL,"CreateEvent");
for (i = 0; i < %<numPeriodicTriggers>; i++) {
rtClock[i] = CreateWaitableTimer(NULL, %, NULL);
CHECK_STATUS(rtClock[i] == NULL,"CreateWaitableTimer");
}
%if (numPeriodicTasks > 0)
%if coreAffinityRequired
GetSystemInfo(&sysinfo);
numCores = sysinfo.dwNumberOfProcessors;
CHECK_STATUS(GetProcessAffinityMask(GetCurrentProcess(), &processMask, &systemMask) == %, "GetProcessAffinityMask");
%endif
/* Create periodic threads */
for (i = 0; i < %<numPeriodicTasks>; i++)
{
periodicThread[i].index = (int_T) i;
periodicThread[i].exitFlag = 0;
/* Create the events that will be used by the thread */
periodicThread[i].startEvent = CreateEvent(NULL, %, %, NULL);
CHECK_STATUS(periodicThread[i].startEvent == NULL, "CreateEvent");
periodicThread[i].stopEvent = CreateEvent(NULL, %, %, NULL);
CHECK_STATUS(periodicThread[i].stopEvent == NULL, "CreateStopEventEvent");
/* Create the thread in suspended mode */
periodicThread[i].threadHandle = (HANDLE)_beginthreadex(NULL, 0, &periodicTask, &periodicThread[i], CREATE_SUSPENDED, &periodicThread[i].threadID);
CHECK_STATUS(periodicThread[i].threadID == 0,"_beginthreadex");
/* Set the thread priority */
CHECK_STATUS(SetThreadPriority(periodicThread[i].threadHandle, priority[i]) == %, "SetThreadPriority");
%if coreAffinityRequired
/* Create the thread mask */
threadMask = 0;
for(j = 0; j < %<maxNumberOfCoresPerTask>; j++) {
if ((coreAffinity[i][j] >= 0) && (coreAffinity[i][j] < numCores))
{
/* Set the (coreAffinity[i][j]+1)th rightmost bit in threadMask */
threadMask |= (1 << coreAffinity[i][j]);
}
}
/* Set the core affinity */
if (threadMask != 0)
{
CHECK_STATUS(SetThreadAffinityMask(periodicThread[i].threadHandle, threadMask) == 0, "SetThreadAffinityMask");
}
%endif
/* Start the thread */
CHECK_STATUS(ResumeThread(periodicThread[i].threadHandle) == -1,"ResumeThread");
}
%endif
/* Create periodic trigger threads */
%assign periodicThreadIDCounter = 0
%foreach ehIdx = LibGetNumTriggers()
%assign evType = LibGetTriggerType(ehIdx)
%if ISEQUAL(evType, "AperiodicTrigger")
%continue
%endif
%if ISEQUAL(LibGetNumTriggerTasks(ehIdx), 0)
%assign threadFcnName = "%<LibGetTriggerName(ehIdx)>"
%assign argStr = "&periodicTriggerThread[%<ehIdx>]"
%assign index = numPeriodicTasks + periodicThreadIDCounter
%assign periodicThreadIDCounter = periodicThreadIDCounter + 1
%else
%assign threadFcnName = "%<LibGetTriggerName(ehIdx)>TaskScheduler"
%assign argStr = "NULL"
%assign index = "0"
%endif
{
periodicTriggerThread[%<ehIdx>].index = %<index>;
periodicTriggerThread[%<ehIdx>].exitFlag = 0;
periodicTriggerThread[%<ehIdx>].startEvent = NULL;
periodicTriggerThread[%<ehIdx>].stopEvent = NULL;
/* Create the thread in suspended mode */
periodicTriggerThread[%<ehIdx>].threadHandle = (HANDLE)_beginthreadex(NULL, 0, &%<threadFcnName>, %<argStr>, CREATE_SUSPENDED, &periodicTriggerThread[%<ehIdx>].threadID);
CHECK_STATUS(periodicTriggerThread[%<ehIdx>].threadHandle == 0,"_beginthreadex");
/* Set the periodic trigger thread priority */
CHECK_STATUS(SetThreadPriority(periodicTriggerThread[%<ehIdx>].threadHandle,THREAD_PRIORITY_HIGHEST) == %, "SetThreadPriority");
/* Start the periodic trigger thread */
CHECK_STATUS(ResumeThread(periodicTriggerThread[%<ehIdx>].threadHandle) == -1,"ResumeThread");
}
%endforeach
%if (numAperiodicTasks > 0)
%assign idx = 0
%foreach aehIdx = LibGetNumTriggers()
%assign evType = LibGetTriggerType(aehIdx)
%if ISEQUAL(evType, "PeriodicTrigger")
%continue
%endif
%assign type = LibGetTriggerHandlerType(aehIdx)
%assign targetObj = LibGetTriggerTargetObject(aehIdx)
%if !ISFIELD(targetObj, "EventName")
%assign errTxt = "Unsupported aperiodic event for native threads."
%<LibReportFatalError(errTxt)>
%endif
%assign eventName = targetObj.EventName
%assign aehName = LibGetTriggerName(aehIdx)
%if ISEQUAL(type, "task")
%assert ISEQUAL(LibGetNumTriggerTasks(aehIdx), 1)
%assign taskIdx = 0
%assign isrFcnName = "%<aehName>_%<taskIdx>"
/* Create aperiodic thread */
%else
/* Create thread for aperiodic trigger */
%assign isrFcnName = "eventHandler_%<aehName>"
%endif
aperiodicThread[%<idx>].index = %<idx>;
aperiodicThread[%<idx>].exitFlag = 0;
aperiodicThread[%<idx>].stopEvent = NULL;
/* Create the event that will trigger the execution of the thread */
aperiodicThread[%<idx>].startEvent = CreateEvent(NULL, %, %, "%<eventName>");
CHECK_STATUS(aperiodicThread[%<idx>].startEvent == NULL, "CreateEvent%<eventName>");
/* Create the thread in suspended mode */
aperiodicThread[%<idx>].threadHandle = (HANDLE)_beginthreadex(NULL, 0, &%<isrFcnName>, &aperiodicThread[%<idx>], CREATE_SUSPENDED, &aperiodicThread[%<idx>].threadID);
CHECK_STATUS(aperiodicThread[%<idx>].threadID == 0,"_beginthreadex");
/* Set the thread priority */
CHECK_STATUS(SetThreadPriority(aperiodicThread[%<idx>].threadHandle, priority[0]) == %, "SetThreadPriority");
/* Start the thread */
CHECK_STATUS(ResumeThread(aperiodicThread[%<idx>].threadHandle) == -1,"ResumeThread");
%assign idx = idx + 1
%endforeach
%endif
/* Real-time scheduling timer */
%foreach ehIdx = LibGetNumTriggers()
%assign evType = LibGetTriggerType(ehIdx)
%if ISEQUAL(evType, "AperiodicTrigger")
%continue
%endif
%assign period = %<LibGetTriggerBaseRate(ehIdx)>
%if ((period * 1000) < 1)
%if LibIsDeploymentDiagram()
%assign errormsg = "The periodic trigger %<LibGetTriggerName(ehIdx)> of model %<::CompiledModel.Name> has a base rate smaller than 1 ms. The current base rate is %<period> seconds. Increase the base rate of the periodic trigger by increasing the rate in the model."
%else
%assign errormsg = "%<::CompiledModel.Name> has a base rate smaller than 1 ms. The current base rate is %<period> seconds. Increase the base rate of the model."
%endif
%exit %<errormsg>
%endif
stNanoSec.QuadPart = (LONGLONG)(%<period> * 1e7 * -1);
stMilliPeriod = (LONG)(%<period> * 1e3);
CHECK_STATUS(SetWaitableTimer(rtClock[%<ehIdx>], &stNanoSec, stMilliPeriod, NULL, NULL, %) == %, "SetWaitableTimer");
%endforeach
/* Wait for a stopping condition. */
for (i = 0; i < %<numPeriodicTriggers>; i++) {
WaitForSingleObject(periodicTriggerThread[i].threadHandle, INFINITE);
}
/* Clean up */
for (i = 0; i< %<numPeriodicTriggers>; i++)
{
if (rtClock[i] != NULL)
{
CloseHandle(rtClock[i]);
}
if (periodicTriggerThread[i].threadHandle != NULL)
{
CloseHandle(periodicTriggerThread[i].threadHandle);
}
}
if (quitEvent != NULL)
{
CloseHandle(quitEvent);
}
%if (numPeriodicTasks > 0)
for (i = 0; i < %<numPeriodicTasks>; i++)
{
if (periodicThread[i].startEvent != NULL)
{
CloseHandle(periodicThread[i].startEvent);
}
if (periodicThread[i].stopEvent != NULL)
{
CloseHandle(periodicThread[i].stopEvent);
}
if (periodicThread[i].threadHandle != NULL)
{
CloseHandle(periodicThread[i].threadHandle);
}
}
%endif
%if (numAperiodicTasks > 0)
for (i = 0; i < %<numAperiodicTasks>; i++)
{
if (aperiodicThread[i].startEvent != NULL)
{
CloseHandle(aperiodicThread[i].startEvent);
}
if (aperiodicThread[i].threadHandle != NULL)
{
CloseHandle(aperiodicThread[i].threadHandle);
}
}
%endif
printf("**stopping the model**/n");
fflush(stdout);
%if !SuppressErrorStatus
if (%<RTMGetErrStat()> != NULL)
{
fprintf(stderr, "/n**%s**/n", %<RTMGetErrStat()>);
}
%endif
%<FcnGenerateModelTerminate()>
%if SLibIsTaskProfilingOn()
writeProfileDataToHTMLFile();
%endif
return 0;
}
%closefile tmpFcnBuf
%<SLibCacheCodeToFile("mainSrc_fcn_defn", tmpFcnBuf)>
%endfunction
%function SLibGenerateThreadedMain() void
%assign numPeriodicTasks = SLibGetNumPeriodicTasks()
%assign numAperiodicTasks = SLibGetNumAperiodicTasks()
%foreach aehIdx = LibGetNumTriggers()
%assign evType = LibGetTriggerType(aehIdx)
%if ISEQUAL(evType, "PeriodicTrigger")
%continue
%endif
%assign type = LibGetTriggerHandlerType(aehIdx)
%if ISEQUAL(type, "isr")
%assign numAperiodicTasks = numAperiodicTasks + 1
%endif
%endforeach
%assign numPeriodicTriggers = SLibGetNumPeriodicTriggers()
%openfile tmpFcnBuf
#ifndef _WIN32
#define _WIN32
#endif
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0500
#endif
#include
#include
%if SLibIsTaskProfilingOn()
#include
#include
%endif
%closefile tmpFcnBuf
%<SLibCacheCodeToFile("mainSrc_incl", tmpFcnBuf)>
%openfile tmpFcnBuf
%if !(::MultiInstanceERTCode && !::UsingMalloc && !::GenerateClassInterface)
%<SLibDeclareModelFcnArgs(TLC_TRUE)>/
%endif
%<SLibDeclareFcnProtoCtlGlobalVariables()>
%if ::UsingMalloc
%<::tSimStructType> *%<::tSimStruct>;
const char *RT_MEMORY_ALLOCATION_ERROR = "memory allocation error";
%endif
%closefile tmpFcnBuf
%<SLibCacheCodeToFile("mainSrc_data_defn", tmpFcnBuf)>
%<FcnGenerateUtilFunctionsAndGlobalVariables(numPeriodicTasks, numAperiodicTasks, ...
numPeriodicTriggers)>
%<FcnGeneratePeriodicTaskWrapperFunctions(numPeriodicTasks, numPeriodicTriggers)>
%<FcnGenerateAperiodicWrapperFunctions()>
%<FcnGenerateMainFunction(numPeriodicTasks, numAperiodicTasks, numPeriodicTriggers)>
%endfunction