|
|
|
|
@@ -0,0 +1,760 @@
|
|
|
|
|
/****************************************************************************
|
|
|
|
|
|
|
|
|
|
|
| (C) Copyright 1985, 1991, 1993, 1996-1998 Novell, Inc.
|
|
|
|
|
| All Rights Reserved.
|
|
|
|
|
|
|
|
|
|
|
| This program is free software; you can redistribute it and/or
|
|
|
|
|
| modify it under the terms of version 2 of the GNU General Public
|
|
|
|
|
| License as published by the Free Software Foundation.
|
|
|
|
|
|
|
|
|
|
|
| This program is distributed in the hope that it will be useful,
|
|
|
|
|
| but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
| GNU General Public License for more details.
|
|
|
|
|
|
|
|
|
|
|
| You should have received a copy of the GNU General Public License
|
|
|
|
|
| along with this program; if not, contact Novell, Inc.
|
|
|
|
|
|
|
|
|
|
|
| To contact Novell about this file by physical or electronic mail,
|
|
|
|
|
| you may find current contact information at www.novell.com
|
|
|
|
|
|
|
|
|
|
|
|***************************************************************************
|
|
|
|
|
|
|
|
|
|
|
| NetWare Advance File Services (NSS) Initialization module
|
|
|
|
|
|
|
|
|
|
|
|---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
| $Author: vandana $
|
|
|
|
|
| $Date: 2007-01-03 04:50:48 +0530 (Wed, 03 Jan 2007) $
|
|
|
|
|
|
|
|
|
|
|
| $RCSfile$
|
|
|
|
|
| $Revision: 1802 $
|
|
|
|
|
|
|
|
|
|
|
|---------------------------------------------------------------------------
|
|
|
|
|
| This module is used to:
|
|
|
|
|
| Routines for allocating and managing structures for
|
|
|
|
|
| spinning off worktodos.
|
|
|
|
|
+-------------------------------------------------------------------------*/
|
|
|
|
|
#include <support/lnxmbINC/procdefs.h> /* NetWare Includes*/
|
|
|
|
|
|
|
|
|
|
#include <library/xStdlib.h> /* NSS Library includes */
|
|
|
|
|
#include <library/xStdio.h>
|
|
|
|
|
#include <include/xError.h>
|
|
|
|
|
#include <include/fsm.h>
|
|
|
|
|
#include <include/xCache.h>
|
|
|
|
|
#include <include/register.h>
|
|
|
|
|
#include <include/schedule.h>
|
|
|
|
|
#include <internal/pssConfig.h>
|
|
|
|
|
#include <include/control.h>
|
|
|
|
|
#include <include/histogram.h>
|
|
|
|
|
#include <include/utc.h>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
NINT WorkWaitingCount = 0;
|
|
|
|
|
NINT WorkHighWaitingCount = 0;
|
|
|
|
|
NINT WorkLowWaitingCount = 0;
|
|
|
|
|
|
|
|
|
|
#define ACTIVE_WORK_WAIT_LIST 0
|
|
|
|
|
#define ACTIVE_WORK_HIGH_WAIT_LIST 1
|
|
|
|
|
|
|
|
|
|
#define WORK_COUNT_HIGH 10
|
|
|
|
|
#define WORK_COUNT_LOW 8
|
|
|
|
|
|
|
|
|
|
CIRhead_t QueuedThreads;
|
|
|
|
|
CIRhead_t QueuedThreadsHigh;
|
|
|
|
|
CIRhead_t WorkWaitingListHead;
|
|
|
|
|
CIRhead_t WorkHighWaitingListHead;
|
|
|
|
|
CIRhead_t WorkLowWaitingListHead;
|
|
|
|
|
NINT ActiveWorkWaitingList = ACTIVE_WORK_WAIT_LIST;
|
|
|
|
|
|
|
|
|
|
#if zLINUX
|
|
|
|
|
extern STATUS kSchedulePrioWorkToDo(struct WorkToDoStructure *work);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/**************************************************************************
|
|
|
|
|
* Because work control needs to use a different dispatch algorithm
|
|
|
|
|
* then other resouce allocation routines, we use the CONTROL initialization
|
|
|
|
|
* but use our own allocation and free routines.
|
|
|
|
|
***************************************************************************/
|
|
|
|
|
typedef struct Work_s
|
|
|
|
|
{
|
|
|
|
|
zWork_s worktodo;
|
|
|
|
|
FsmLite_s *fsm;
|
|
|
|
|
#if NSS_DEBUG IS_ENABLED
|
|
|
|
|
LONG magic;
|
|
|
|
|
char *name;
|
|
|
|
|
NINT instance;
|
|
|
|
|
#endif
|
|
|
|
|
} Work_s;
|
|
|
|
|
|
|
|
|
|
ControlStore_s WorkControl;
|
|
|
|
|
ControlStore_s WorkControlHigh;
|
|
|
|
|
ControlStore_s WorkControlLow;
|
|
|
|
|
NINT PendingWork = 0;
|
|
|
|
|
|
|
|
|
|
extern void WORK_Run(Work_s *work);
|
|
|
|
|
extern void WORK_RunHigh(Work_s *work);
|
|
|
|
|
extern void WORK_RunLow(Work_s *work);
|
|
|
|
|
|
|
|
|
|
/**************************************************************************
|
|
|
|
|
*
|
|
|
|
|
***************************************************************************/
|
|
|
|
|
void WORK_Init (Work_s *work)
|
|
|
|
|
{
|
|
|
|
|
work->worktodo.ProcedureToCall = WORK_Run;
|
|
|
|
|
work->worktodo.WorkResourceTag = COMN_Resource.workToDoRTag;
|
|
|
|
|
|
|
|
|
|
#if NSS_DEBUG IS_ENABLED
|
|
|
|
|
{
|
|
|
|
|
static NINT instance = 0;
|
|
|
|
|
|
|
|
|
|
work->magic = 0xbaddad;
|
|
|
|
|
work->name = MSGNot("Work");
|
|
|
|
|
work->instance = instance++;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void WORK_InitHigh (Work_s *work)
|
|
|
|
|
{
|
|
|
|
|
work->worktodo.ProcedureToCall = WORK_RunHigh;
|
|
|
|
|
work->worktodo.WorkResourceTag = COMN_Resource.workToDoRTag;
|
|
|
|
|
|
|
|
|
|
#if NSS_DEBUG IS_ENABLED
|
|
|
|
|
{
|
|
|
|
|
static NINT instance = 0;
|
|
|
|
|
|
|
|
|
|
work->magic = 0xbaddad;
|
|
|
|
|
work->name = MSGNot("WorkHigh");
|
|
|
|
|
work->instance = instance++;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void WORK_InitLow (Work_s *work)
|
|
|
|
|
{
|
|
|
|
|
work->worktodo.ProcedureToCall = WORK_RunLow;
|
|
|
|
|
work->worktodo.WorkResourceTag = COMN_Resource.workToDoRTag;
|
|
|
|
|
|
|
|
|
|
#if NSS_DEBUG IS_ENABLED
|
|
|
|
|
{
|
|
|
|
|
static NINT instance = 0;
|
|
|
|
|
|
|
|
|
|
work->magic = 0xbaddad;
|
|
|
|
|
work->name = MSGNot("WorkLow");
|
|
|
|
|
work->instance = instance++;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if NSS_DEBUG IS_ENABLED
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This code is used to verify that WORK_Schedule() is running threads
|
|
|
|
|
* within an acceptable time frame. This was written because under
|
|
|
|
|
* MOAB we saw some threads not ruuning for numerous seconds.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#define TT_NOT_RUNNING 0
|
|
|
|
|
#define TT_RUNNING 1
|
|
|
|
|
#define TT_ABORT_REQUEST 2
|
|
|
|
|
|
|
|
|
|
int gNSSThreadTestState = TT_NOT_RUNNING;
|
|
|
|
|
QUAD gNSSThreadTestCount = 0;
|
|
|
|
|
Time_t gNSSThreadTestTimeLast;
|
|
|
|
|
Time_t gNSSThreadTestTimeAssert = 20; /* Number of seconds before asserting */
|
|
|
|
|
Time_t gNSSThreadTestTimeMax; /* Max seconds */
|
|
|
|
|
Time_t gNSSThreadTestTimeMaxTime; /* When max occurred */
|
|
|
|
|
FsmLite_s gNSSThreadTestWorkToDoFsm;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void WORK_ThreadTestWorkToDoRoutine( FsmLite_s *workToDoFsm )
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
Time_t cTime;
|
|
|
|
|
Time_t diffTime;
|
|
|
|
|
char buffer[40];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
WORK_PROCESS_INIT();
|
|
|
|
|
|
|
|
|
|
++gNSSThreadTestCount;
|
|
|
|
|
if ( gNSSThreadTestCount < 2 )
|
|
|
|
|
{
|
|
|
|
|
DBG_DebugPrintf(CYAN,MSGNot("Thread Test is running ...\n"));
|
|
|
|
|
}
|
|
|
|
|
cTime = GetUTCTime();
|
|
|
|
|
if ( cTime < gNSSThreadTestTimeLast )
|
|
|
|
|
{ /* NetWare sometimes sets the clock back a little */
|
|
|
|
|
diffTime = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
diffTime = cTime - gNSSThreadTestTimeLast;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( diffTime >= gNSSThreadTestTimeAssert )
|
|
|
|
|
{
|
|
|
|
|
DBG_DebugPrintf( LRED,
|
|
|
|
|
MSGNot("NSS Thread Test schedule delayed for %lu seconds ending at %s.\n"),
|
|
|
|
|
(unsigned long)diffTime, UTCTime2Str(cTime,&buffer[0]) );
|
|
|
|
|
//
|
|
|
|
|
// Because we can queue up a lot of pending work, this is not that unusual
|
|
|
|
|
//
|
|
|
|
|
// /* We print to screen so that testers can see delay time */
|
|
|
|
|
// aprintf(LRED,
|
|
|
|
|
MSGNot("NSS Thread Test schedule delayed for %lu seconds ending at %s.\n"),
|
|
|
|
|
// (unsigned long)diffTime, UTCTime2Str(cTime,&buffer[0]) );
|
|
|
|
|
// zASSERT( "It appears that scheduling is really slow" == NULL );
|
|
|
|
|
//
|
|
|
|
|
}
|
|
|
|
|
/* Is this the maximum delay for a schedule? */
|
|
|
|
|
if ( diffTime > gNSSThreadTestTimeMax )
|
|
|
|
|
{ /* Yes - update max time and when max time occurred. */
|
|
|
|
|
gNSSThreadTestTimeMax = diffTime;
|
|
|
|
|
gNSSThreadTestTimeMaxTime = cTime;
|
|
|
|
|
/* Display in debugger buffer */
|
|
|
|
|
DBG_DebugPrintf( LRED,
|
|
|
|
|
MSGNot("NSS Thread Test new MAX delay of %lu seconds ending at %s.\n"),
|
|
|
|
|
(unsigned long)gNSSThreadTestTimeMax,
|
|
|
|
|
UTCTime2Str(gNSSThreadTestTimeMaxTime,&buffer[0]) );
|
|
|
|
|
}
|
|
|
|
|
LB_delay( 1 * 1000 ); /* 1 second delay - can not do a yield because
|
|
|
|
|
* GreenRiver was complaining that low priority
|
|
|
|
|
* threads were not being allowed to run.
|
|
|
|
|
*/
|
|
|
|
|
/* Should we continue running the test? */
|
|
|
|
|
if ( gNSSThreadTestState == TT_RUNNING )
|
|
|
|
|
{ /* Yes - reset time and re-schedule */
|
|
|
|
|
gNSSThreadTestTimeLast = GetUTCTime();
|
|
|
|
|
WORK_Schedule( &gNSSThreadTestWorkToDoFsm,
|
|
|
|
|
WORK_ThreadTestWorkToDoRoutine, 0);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
/* Mark that we are not running the test anymore */
|
|
|
|
|
DBG_DebugPrintf(CYAN,MSGNot("... Thread Test has stopped\n"));
|
|
|
|
|
gNSSThreadTestState = TT_NOT_RUNNING;
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
} /* End of WORK_ThreadTestWorkToDoRoutine() */
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/**************************************************************************
|
|
|
|
|
*
|
|
|
|
|
***************************************************************************/
|
|
|
|
|
STATUS WORK_Startup (void)
|
|
|
|
|
{
|
|
|
|
|
STATUS status;
|
|
|
|
|
ASSERT_MPKNSS_LOCK();
|
|
|
|
|
|
|
|
|
|
CIR_INIT(QueuedThreads);
|
|
|
|
|
CIR_INIT(QueuedThreadsHigh);
|
|
|
|
|
CIR_INIT(WorkWaitingListHead);
|
|
|
|
|
CIR_INIT(WorkHighWaitingListHead);
|
|
|
|
|
CIR_INIT(WorkLowWaitingListHead);
|
|
|
|
|
|
|
|
|
|
status = CONTROL_Startup( &WorkControl, Config.os.workLimit,
|
|
|
|
|
sizeof(Work_s), (voidfunc_t)WORK_Init);
|
|
|
|
|
status = CONTROL_Startup( &WorkControlHigh, WORK_COUNT_HIGH,
|
|
|
|
|
sizeof(Work_s), (voidfunc_t)WORK_InitHigh);
|
|
|
|
|
status = CONTROL_Startup( &WorkControlLow, WORK_COUNT_LOW,
|
|
|
|
|
sizeof(Work_s), (voidfunc_t)WORK_InitLow);
|
|
|
|
|
|
|
|
|
|
#if NSS_DEBUG IS_ENABLED
|
|
|
|
|
FSMLITE_INIT( &gNSSThreadTestWorkToDoFsm /* Lite FSM */,
|
|
|
|
|
MSGNot("Thread test Work-To-Do"), 0 /* Instance */ );
|
|
|
|
|
#if zLINUX
|
|
|
|
|
gNSSThreadTestState = TT_NOT_RUNNING;
|
|
|
|
|
#else
|
|
|
|
|
gNSSThreadTestState = TT_RUNNING;
|
|
|
|
|
gNSSThreadTestTimeLast = GetUTCTime();
|
|
|
|
|
WORK_Schedule( &gNSSThreadTestWorkToDoFsm,
|
|
|
|
|
WORK_ThreadTestWorkToDoRoutine, 0);
|
|
|
|
|
#endif // zLINUX
|
|
|
|
|
|
|
|
|
|
#endif // NSS_DEBUG IS_ENABLED
|
|
|
|
|
|
|
|
|
|
#if MEM_KEEP_LIST IS_ENABLED
|
|
|
|
|
/* We must wait until at least the timer AND work code is inited because
|
|
|
|
|
* free will schedule a one shot (that will call work) (it is not doing immediate
|
|
|
|
|
* frees).
|
|
|
|
|
*/
|
|
|
|
|
MKL_AllocStart();
|
|
|
|
|
#endif // MEM_KEEP_LIST IS_ENABLED
|
|
|
|
|
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**************************************************************************
|
|
|
|
|
* This will wait for pending work to drain. This should wait on the order
|
|
|
|
|
* of 10 seconds.
|
|
|
|
|
***************************************************************************/
|
|
|
|
|
void WORK_WaitForPending()
|
|
|
|
|
{
|
|
|
|
|
NINT delayCount;
|
|
|
|
|
NINT okCount = 0;
|
|
|
|
|
|
|
|
|
|
/* FixFixFix6 - zfsPool.c and beastStartup.c call this routine
|
|
|
|
|
* to let threads finish up when a 'volume' is being shutdown.
|
|
|
|
|
* This is a little bogus because this routine waits for all
|
|
|
|
|
* threads to complete, not just the threads working on the
|
|
|
|
|
* 'volume' being shutdown. I believe the rational is that
|
|
|
|
|
* on shutdown all volumes will be shutdown, although I am
|
|
|
|
|
* not sure this is true because I assume you can unload a single
|
|
|
|
|
* LSS that would only cause its volumes to shutdown.
|
|
|
|
|
*/
|
|
|
|
|
#if NSS_DEBUG IS_ENABLED
|
|
|
|
|
/* In debug mode we have one thread that runs all the time.
|
|
|
|
|
* Do special code so we do not wait '10 seconds' on
|
|
|
|
|
* each volumes shutdown.
|
|
|
|
|
*/
|
|
|
|
|
/* Is special thread still running? */
|
|
|
|
|
if ( gNSSThreadTestState == TT_RUNNING )
|
|
|
|
|
{ /* YES - then delay until only one thread running */
|
|
|
|
|
okCount = 1;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
for (delayCount = Config.os.workDelayCnt;
|
|
|
|
|
(PendingWork != okCount) && (delayCount > 0);
|
|
|
|
|
--delayCount)
|
|
|
|
|
{
|
|
|
|
|
LB_delay(Config.msec_s.workWait);
|
|
|
|
|
}
|
|
|
|
|
#ifdef __linux__
|
|
|
|
|
if (PendingWork != okCount)
|
|
|
|
|
{
|
|
|
|
|
LB_aprintf(0, ".........PendingWork=%d okCount=%d, delayCount=%d\n", PendingWork, okCount, delayCount);
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
zASSERT(PendingWork == okCount);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**************************************************************************
|
|
|
|
|
* This will wait up to 10 seconds for the work to finish processing
|
|
|
|
|
***************************************************************************/
|
|
|
|
|
void WORK_Shutdown (void)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
#if MEM_KEEP_LIST IS_ENABLED
|
|
|
|
|
MKL_AllocStop();
|
|
|
|
|
#endif
|
|
|
|
|
#if NSS_DEBUG IS_ENABLED
|
|
|
|
|
/* Wait for our thread test to stop - this works even if the test
|
|
|
|
|
* was not started.
|
|
|
|
|
*/
|
|
|
|
|
while ( gNSSThreadTestState != TT_NOT_RUNNING )
|
|
|
|
|
{
|
|
|
|
|
gNSSThreadTestState = TT_ABORT_REQUEST; /* Request thread test to stop */
|
|
|
|
|
Yield();
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
WORK_WaitForPending();
|
|
|
|
|
CONTROL_Shutdown( &WorkControl);
|
|
|
|
|
CONTROL_Shutdown( &WorkControlHigh);
|
|
|
|
|
CONTROL_Shutdown( &WorkControlLow);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**************************************************************************
|
|
|
|
|
* This is the MAIN routine you should call when you want to create
|
|
|
|
|
* WorkToDo's.
|
|
|
|
|
***************************************************************************/
|
|
|
|
|
void WORK_Schedule (FsmLite_s *fsm, voidfunc_t action, ADDR parameter)
|
|
|
|
|
{
|
|
|
|
|
FakeControl_s *fake;
|
|
|
|
|
Work_s *work;
|
|
|
|
|
|
|
|
|
|
ENTER(TFSM, WORK_Schedule);
|
|
|
|
|
ASSERT_MPKNSS_LOCK();
|
|
|
|
|
|
|
|
|
|
INC_HISTOGRAM(WorkControl.histogram);
|
|
|
|
|
|
|
|
|
|
fsm->action = (voidfunc_t)action;
|
|
|
|
|
fsm->param.user = parameter;
|
|
|
|
|
|
|
|
|
|
STK_POP(WorkControl.head.freeList, fake, FakeControl_s, link);
|
|
|
|
|
|
|
|
|
|
if (fake == NULL)
|
|
|
|
|
{
|
|
|
|
|
CIR_ENQ(WorkWaitingListHead, fsm, link);
|
|
|
|
|
WorkWaitingCount++;
|
|
|
|
|
/* This can not be here because this routine is called from
|
|
|
|
|
* a FastWorkToDo which can't yield
|
|
|
|
|
*/
|
|
|
|
|
//Yield(); // I hate this. Paul T.
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
PendingWork++;
|
|
|
|
|
work = (Work_s *)&fake->link;
|
|
|
|
|
work->fsm = fsm;
|
|
|
|
|
ScheduleWork(work);
|
|
|
|
|
}
|
|
|
|
|
RTN_VOID();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**************************************************************************
|
|
|
|
|
* This is the MAIN routine you should call when you want to create
|
|
|
|
|
* WorkToDo's, and scheule them with a higher priority if put on the
|
|
|
|
|
* waiting list.
|
|
|
|
|
***************************************************************************/
|
|
|
|
|
void WORK_Schedule_HIGH (FsmLite_s *fsm, voidfunc_t action, ADDR parameter)
|
|
|
|
|
{
|
|
|
|
|
FakeControl_s *fake;
|
|
|
|
|
Work_s *work;
|
|
|
|
|
|
|
|
|
|
ENTER(TFSM, WORK_Schedule);
|
|
|
|
|
INC_HISTOGRAM(WorkControlHigh.histogram);
|
|
|
|
|
|
|
|
|
|
fsm->action = (voidfunc_t)action;
|
|
|
|
|
fsm->param.user = parameter;
|
|
|
|
|
|
|
|
|
|
STK_POP(WorkControlHigh.head.freeList, fake, FakeControl_s, link);
|
|
|
|
|
|
|
|
|
|
if (fake == NULL)
|
|
|
|
|
{
|
|
|
|
|
CIR_ENQ(WorkHighWaitingListHead, fsm, link);
|
|
|
|
|
WorkHighWaitingCount++;
|
|
|
|
|
/* This can not be here because this routine is called from
|
|
|
|
|
* a FastWorkToDo which can't yield
|
|
|
|
|
*/
|
|
|
|
|
//Yield(); // I hate this. Paul T.
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
PendingWork++;
|
|
|
|
|
work = (Work_s *)&fake->link;
|
|
|
|
|
work->fsm = fsm;
|
|
|
|
|
#if zLINUX
|
|
|
|
|
MPKNSS_UNLOCK();
|
|
|
|
|
kSchedulePrioWorkToDo((struct WorkToDoStructure *)work);
|
|
|
|
|
MPKNSS_LOCK();
|
|
|
|
|
#else
|
|
|
|
|
ScheduleWork(work);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
RTN_VOID();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**************************************************************************
|
|
|
|
|
* This routine queues up work for a WorkToDo but does not start it. The
|
|
|
|
|
* queued items will be handled by an already running WorkToDo. If no
|
|
|
|
|
* WorkToDo is started then it will start one.
|
|
|
|
|
***************************************************************************/
|
|
|
|
|
void WORK_Queue (FsmLite_s *fsm, voidfunc_t action, ADDR parameter)
|
|
|
|
|
{
|
|
|
|
|
fsm->action = (voidfunc_t)action;
|
|
|
|
|
fsm->param.user = parameter;
|
|
|
|
|
|
|
|
|
|
if (PendingWork > 0)
|
|
|
|
|
{
|
|
|
|
|
CIR_ENQ(WorkLowWaitingListHead, fsm, link);
|
|
|
|
|
WorkLowWaitingCount++;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
WORK_Schedule(fsm, action, parameter);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**************************************************************************
|
|
|
|
|
* This is the MAIN routine you should call when you want to create
|
|
|
|
|
* WorkToDo's, and scheule them with a lower priority if put on the
|
|
|
|
|
* waiting list.
|
|
|
|
|
***************************************************************************/
|
|
|
|
|
void WORK_Schedule_LOW (FsmLite_s *fsm, voidfunc_t action, ADDR parameter)
|
|
|
|
|
{
|
|
|
|
|
FakeControl_s *fake;
|
|
|
|
|
Work_s *work;
|
|
|
|
|
|
|
|
|
|
ENTER(TFSM, WORK_Schedule);
|
|
|
|
|
INC_HISTOGRAM(WorkControlLow.histogram);
|
|
|
|
|
|
|
|
|
|
fsm->action = (voidfunc_t)action;
|
|
|
|
|
fsm->param.user = parameter;
|
|
|
|
|
|
|
|
|
|
STK_POP(WorkControlLow.head.freeList, fake, FakeControl_s, link);
|
|
|
|
|
|
|
|
|
|
if (fake == NULL)
|
|
|
|
|
{
|
|
|
|
|
CIR_ENQ(WorkLowWaitingListHead, fsm, link);
|
|
|
|
|
WorkLowWaitingCount++;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
PendingWork++;
|
|
|
|
|
work = (Work_s *)&fake->link;
|
|
|
|
|
work->fsm = fsm;
|
|
|
|
|
ScheduleWork(work);
|
|
|
|
|
}
|
|
|
|
|
RTN_VOID();
|
|
|
|
|
}
|
|
|
|
|
WorkInst_s WorkInst = { 0 };
|
|
|
|
|
|
|
|
|
|
/**************************************************************************
|
|
|
|
|
* This is the routine that is called to execute workToDo code.
|
|
|
|
|
***************************************************************************/
|
|
|
|
|
void WORK_Run (Work_s *work)
|
|
|
|
|
{
|
|
|
|
|
FakeControl_s *fake;
|
|
|
|
|
FsmLite_s *fsm = work->fsm;
|
|
|
|
|
#if NSS_DEBUG IS_ENABLED
|
|
|
|
|
NINT displayedDebug = FALSE;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
Enable();
|
|
|
|
|
MPKNSS_LOCK();
|
|
|
|
|
|
|
|
|
|
//ENTER(TFSM, WORK_Run);
|
|
|
|
|
++WorkInst.enter;
|
|
|
|
|
for (;;)
|
|
|
|
|
{
|
|
|
|
|
++WorkInst.loop;
|
|
|
|
|
#if NSS_DEBUG IS_ENABLED
|
|
|
|
|
if (!displayedDebug)
|
|
|
|
|
{
|
|
|
|
|
displayedDebug = TRUE;
|
|
|
|
|
DEBUG_PRINTF(TYIELDS,DBG_BOTH_NOINDENT,(LRED,
|
|
|
|
|
MSGNot("Scheduling WORK (Thread=%08x)\n"),ThreadId()));
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
((void (*)(FsmLite_s *, ADDR))fsm->action)(fsm, fsm->param.user);
|
|
|
|
|
CHECK_INTERRUPTS();
|
|
|
|
|
|
|
|
|
|
DEC_HISTOGRAM(WorkControl.histogram);
|
|
|
|
|
|
|
|
|
|
if (ActiveWorkWaitingList == ACTIVE_WORK_WAIT_LIST)
|
|
|
|
|
{
|
|
|
|
|
if (CIR_NOT_EMPTY(WorkWaitingListHead))
|
|
|
|
|
{
|
|
|
|
|
++WorkInst.reuse;
|
|
|
|
|
CIR_DEQ_NO_CHECK(WorkWaitingListHead, fsm, FsmLite_s, link);
|
|
|
|
|
ActiveWorkWaitingList = ACTIVE_WORK_HIGH_WAIT_LIST;
|
|
|
|
|
WorkWaitingCount--;
|
|
|
|
|
// SIGNAL_NEXT_THREAD();
|
|
|
|
|
PERIODIC_YIELD();
|
|
|
|
|
++WorkInst.yield;
|
|
|
|
|
}
|
|
|
|
|
else if (CIR_NOT_EMPTY(WorkHighWaitingListHead))
|
|
|
|
|
{
|
|
|
|
|
++WorkInst.reuse;
|
|
|
|
|
CIR_DEQ_NO_CHECK(WorkHighWaitingListHead, fsm, FsmLite_s, link);
|
|
|
|
|
ActiveWorkWaitingList = ACTIVE_WORK_WAIT_LIST;
|
|
|
|
|
WorkHighWaitingCount--;
|
|
|
|
|
// SIGNAL_NEXT_THREAD_HIGH();
|
|
|
|
|
PERIODIC_YIELD();
|
|
|
|
|
++WorkInst.yield;
|
|
|
|
|
}
|
|
|
|
|
else if (CIR_NOT_EMPTY(WorkLowWaitingListHead))
|
|
|
|
|
{
|
|
|
|
|
++WorkInst.reuse;
|
|
|
|
|
CIR_DEQ_NO_CHECK(WorkLowWaitingListHead, fsm, FsmLite_s, link);
|
|
|
|
|
WorkLowWaitingCount--;
|
|
|
|
|
PERIODIC_YIELD();
|
|
|
|
|
++WorkInst.yield;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
fake = STRUCT(work, FakeControl_s, link);
|
|
|
|
|
NULLIFY( &fake->link);
|
|
|
|
|
STK_PUSH(WorkControl.head.freeList, fake, link);
|
|
|
|
|
zASSERT(PendingWork > 0);
|
|
|
|
|
PendingWork--;
|
|
|
|
|
++WorkInst.exit;
|
|
|
|
|
|
|
|
|
|
#if NSS_DEBUG IS_ENABLED
|
|
|
|
|
if (displayedDebug)
|
|
|
|
|
{
|
|
|
|
|
DEBUG_PRINTF(TYIELDS,DBG_BOTH_NOINDENT,(LRED,
|
|
|
|
|
MSGNot("Stopped Scheduling WORK (Thread=%08x)\n"),ThreadId()));
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
//RTN_VOID();
|
|
|
|
|
MPKNSS_UNLOCK();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (CIR_NOT_EMPTY(WorkHighWaitingListHead))
|
|
|
|
|
{
|
|
|
|
|
++WorkInst.reuse;
|
|
|
|
|
CIR_DEQ_NO_CHECK(WorkHighWaitingListHead, fsm, FsmLite_s, link);
|
|
|
|
|
ActiveWorkWaitingList = ACTIVE_WORK_WAIT_LIST;
|
|
|
|
|
WorkHighWaitingCount--;
|
|
|
|
|
// SIGNAL_NEXT_THREAD_HIGH();
|
|
|
|
|
PERIODIC_YIELD();
|
|
|
|
|
++WorkInst.yield;
|
|
|
|
|
}
|
|
|
|
|
else if (CIR_NOT_EMPTY(WorkWaitingListHead))
|
|
|
|
|
{
|
|
|
|
|
++WorkInst.reuse;
|
|
|
|
|
CIR_DEQ_NO_CHECK(WorkWaitingListHead, fsm, FsmLite_s, link);
|
|
|
|
|
ActiveWorkWaitingList = ACTIVE_WORK_HIGH_WAIT_LIST;
|
|
|
|
|
WorkWaitingCount--;
|
|
|
|
|
// SIGNAL_NEXT_THREAD();
|
|
|
|
|
PERIODIC_YIELD();
|
|
|
|
|
++WorkInst.yield;
|
|
|
|
|
}
|
|
|
|
|
else if (CIR_NOT_EMPTY(WorkLowWaitingListHead))
|
|
|
|
|
{
|
|
|
|
|
++WorkInst.reuse;
|
|
|
|
|
CIR_DEQ_NO_CHECK(WorkLowWaitingListHead, fsm, FsmLite_s, link);
|
|
|
|
|
WorkLowWaitingCount--;
|
|
|
|
|
PERIODIC_YIELD();
|
|
|
|
|
++WorkInst.yield;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
fake = STRUCT(work, FakeControl_s, link);
|
|
|
|
|
NULLIFY( &fake->link);
|
|
|
|
|
STK_PUSH(WorkControl.head.freeList, fake, link);
|
|
|
|
|
zASSERT(PendingWork > 0);
|
|
|
|
|
PendingWork--;
|
|
|
|
|
++WorkInst.exit;
|
|
|
|
|
|
|
|
|
|
#if NSS_DEBUG IS_ENABLED
|
|
|
|
|
if (displayedDebug)
|
|
|
|
|
{
|
|
|
|
|
DEBUG_PRINTF(TYIELDS,DBG_BOTH_NOINDENT,(LRED,
|
|
|
|
|
MSGNot("Stopped Scheduling WORK (Thread=%08x)\n"),ThreadId()));
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
//RTN_VOID();
|
|
|
|
|
MPKNSS_UNLOCK();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void WORK_RunHigh (Work_s *work)
|
|
|
|
|
{
|
|
|
|
|
FakeControl_s *fake;
|
|
|
|
|
FsmLite_s *fsm = work->fsm;
|
|
|
|
|
#if NSS_DEBUG IS_ENABLED
|
|
|
|
|
NINT displayedDebug = FALSE;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
Enable();
|
|
|
|
|
MPKNSS_LOCK();
|
|
|
|
|
|
|
|
|
|
//ENTER(TFSM, WORK_Run);
|
|
|
|
|
++WorkInst.enter;
|
|
|
|
|
for (;;)
|
|
|
|
|
{
|
|
|
|
|
++WorkInst.loop;
|
|
|
|
|
#if NSS_DEBUG IS_ENABLED
|
|
|
|
|
if (!displayedDebug)
|
|
|
|
|
{
|
|
|
|
|
displayedDebug = TRUE;
|
|
|
|
|
DEBUG_PRINTF(TYIELDS,DBG_BOTH_NOINDENT,(LRED,
|
|
|
|
|
MSGNot("Scheduling WORK (Thread=%08x)\n"),ThreadId()));
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
((void (*)(FsmLite_s *, ADDR))fsm->action)(fsm, fsm->param.user);
|
|
|
|
|
CHECK_INTERRUPTS();
|
|
|
|
|
|
|
|
|
|
DEC_HISTOGRAM(WorkControlHigh.histogram);
|
|
|
|
|
|
|
|
|
|
if (CIR_NOT_EMPTY(WorkHighWaitingListHead))
|
|
|
|
|
{
|
|
|
|
|
++WorkInst.reuse;
|
|
|
|
|
CIR_DEQ_NO_CHECK(WorkHighWaitingListHead, fsm, FsmLite_s, link);
|
|
|
|
|
WorkHighWaitingCount--;
|
|
|
|
|
// SIGNAL_NEXT_THREAD_HIGH();
|
|
|
|
|
PERIODIC_YIELD();
|
|
|
|
|
++WorkInst.yield;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
fake = STRUCT(work, FakeControl_s, link);
|
|
|
|
|
NULLIFY( &fake->link);
|
|
|
|
|
STK_PUSH(WorkControlHigh.head.freeList, fake, link);
|
|
|
|
|
zASSERT(PendingWork > 0);
|
|
|
|
|
PendingWork--;
|
|
|
|
|
++WorkInst.exit;
|
|
|
|
|
|
|
|
|
|
#if NSS_DEBUG IS_ENABLED
|
|
|
|
|
if (displayedDebug)
|
|
|
|
|
{
|
|
|
|
|
DEBUG_PRINTF(TYIELDS,DBG_BOTH_NOINDENT,(LRED,
|
|
|
|
|
MSGNot("Stopped Scheduling WORK (Thread=%08x)\n"),ThreadId()));
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
//RTN_VOID();
|
|
|
|
|
MPKNSS_UNLOCK();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void WORK_RunLow (Work_s *work)
|
|
|
|
|
{
|
|
|
|
|
FakeControl_s *fake;
|
|
|
|
|
FsmLite_s *fsm = work->fsm;
|
|
|
|
|
#if NSS_DEBUG IS_ENABLED
|
|
|
|
|
NINT displayedDebug = FALSE;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
Enable();
|
|
|
|
|
MPKNSS_LOCK();
|
|
|
|
|
|
|
|
|
|
//ENTER(TFSM, WORK_Run);
|
|
|
|
|
++WorkInst.enter;
|
|
|
|
|
for (;;)
|
|
|
|
|
{
|
|
|
|
|
++WorkInst.loop;
|
|
|
|
|
#if NSS_DEBUG IS_ENABLED
|
|
|
|
|
if (!displayedDebug)
|
|
|
|
|
{
|
|
|
|
|
displayedDebug = TRUE;
|
|
|
|
|
DEBUG_PRINTF(TYIELDS,DBG_BOTH_NOINDENT,(LRED,
|
|
|
|
|
MSGNot("Scheduling WORK (Thread=%08x)\n"),ThreadId()));
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
((void (*)(FsmLite_s *, ADDR))fsm->action)(fsm, fsm->param.user);
|
|
|
|
|
CHECK_INTERRUPTS();
|
|
|
|
|
|
|
|
|
|
DEC_HISTOGRAM(WorkControlLow.histogram);
|
|
|
|
|
|
|
|
|
|
if (CIR_NOT_EMPTY(WorkLowWaitingListHead))
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
++WorkInst.reuse;
|
|
|
|
|
CIR_DEQ_NO_CHECK(WorkLowWaitingListHead, fsm, FsmLite_s, link);
|
|
|
|
|
WorkLowWaitingCount--;
|
|
|
|
|
// SIGNAL_NEXT_THREAD_HIGH();
|
|
|
|
|
PERIODIC_YIELD();
|
|
|
|
|
++WorkInst.yield;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
fake = STRUCT(work, FakeControl_s, link);
|
|
|
|
|
NULLIFY( &fake->link);
|
|
|
|
|
STK_PUSH(WorkControlLow.head.freeList, fake, link);
|
|
|
|
|
zASSERT(PendingWork > 0);
|
|
|
|
|
PendingWork--;
|
|
|
|
|
++WorkInst.exit;
|
|
|
|
|
|
|
|
|
|
#if NSS_DEBUG IS_ENABLED
|
|
|
|
|
if (displayedDebug)
|
|
|
|
|
{
|
|
|
|
|
DEBUG_PRINTF(TYIELDS,DBG_BOTH_NOINDENT,(LRED,
|
|
|
|
|
MSGNot("Stopped Scheduling WORK (Thread=%08x)\n"),ThreadId()));
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
//RTN_VOID();
|
|
|
|
|
MPKNSS_UNLOCK();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|