0525 core: import NSS cache work scheduling runtime

This commit is contained in:
Mario Fetka
2026-06-14 09:34:30 +00:00
parent 7d46ba8c4e
commit b02a252b5b
8 changed files with 895 additions and 6 deletions

View File

@@ -104,6 +104,27 @@ extern void fillInWork(
voidfunc_t procedureToCall,
void *userParameter);
extern STATUS ZOS_ScheduleWorkToDo(struct WorkToDoStructure *work);
extern STATUS ZOS_ScheduleFastWorkToDo(struct WorkToDoStructure *work, int priority);
extern STATUS ZOS_CancelWorkToDo(struct WorkToDoStructure *work);
#define ScheduleWork(_work) \
ZOS_ScheduleWorkToDo((struct WorkToDoStructure *)(_work))
#define ScheduleFastWork(_work) \
ZOS_ScheduleFastWorkToDo((struct WorkToDoStructure *)(_work), 1)
#define CancelWork(_work) \
ZOS_CancelWorkToDo((struct WorkToDoStructure *)(_work))
#ifndef PERIODIC_YIELD_COUNT
#define PERIODIC_YIELD_COUNT 50
#endif
#ifndef PERIODIC_YIELD
#define PERIODIC_YIELD() Yield()
#endif
#ifndef CHECK_INTERRUPTS
#define CHECK_INTERRUPTS() ((void)0)
#endif
#define Wait() ZOS_Sleep()
#define Continue(pid) ZOS_WakeUp((THREAD)(pid))
#define Yield() ZOS_YieldThread()
@@ -228,14 +249,14 @@ extern STATUS DestroyThread(
LONG threadID);
/* MP APIs*/
extern ERROR kDestroyThread(THREAD ThreadHandle);
extern STATUS kDestroyThread(THREAD ThreadHandle);
extern THREAD kCurrentThread(void);
extern ERROR kDelayThread(unsigned int);
extern STATUS kDelayThread(unsigned int);
#define ThreadId() (ADDR)kCurrentThread()
extern ERROR kWakeUp(THREAD);
extern STATUS kWakeUp(THREAD);
extern void kSleep();
extern void kYieldThread();
@@ -408,9 +429,9 @@ typedef struct zWorkProc2_s
extern ERROR kScheduleWorkToDo(struct WorkToDoStructure *);
extern ERROR kScheduleFastWorkTo(struct WorkToDoStructure *);
extern ERROR kCancelWorkToDo(struct WorkToDoStructure *);
extern STATUS kScheduleWorkToDo(struct WorkToDoStructure *);
extern STATUS kScheduleFastWorkTo(struct WorkToDoStructure *);
extern STATUS kCancelWorkToDo(struct WorkToDoStructure *);
#define ScheduleWork(_work) \

View File

@@ -145,6 +145,7 @@ add_library(nwcore SHARED
nss/cache/control.c
nss/cache/asyncio.c
nss/cache/bond.c
nss/cache/work.c
library/fsm/fsmnw.c
library/latch/intlatch.c
library/latch/latch.c

View File

@@ -43,6 +43,7 @@
#include <include/pssmpk.h>
#include <include/schedule.h>
#include <include/xError.h>
/**************************************************************************
* Delay the given number of milliseconeds
@@ -107,3 +108,40 @@ LONG GetSuperHighResolutionTimer(void)
clock_gettime(CLOCK_MONOTONIC, &now);
return (LONG)(now.tv_sec * 1000000L + now.tv_nsec / 1000L);
}
STATUS ZOS_ScheduleWorkToDo(struct WorkToDoStructure *work)
{
zWork_s *zwork = (zWork_s *)work;
BOOL hadLock = MPKNSS_I_OWN_SPINLOCK();
if (zwork == NULL || zwork->ProcedureToCall == NULL)
{
return zERR_BAD_PARAMETER_VALUE;
}
if (hadLock)
{
MPKNSS_UNLOCK();
}
((void (*)(void *))zwork->ProcedureToCall)(work);
if (hadLock)
{
MPKNSS_LOCK();
}
return zOK;
}
STATUS ZOS_ScheduleFastWorkToDo(struct WorkToDoStructure *work, int priority)
{
(void)priority;
return ZOS_ScheduleWorkToDo(work);
}
STATUS ZOS_CancelWorkToDo(struct WorkToDoStructure *work)
{
(void)work;
return zOK;
}

760
src/core/nss/cache/work.c vendored Normal file
View File

@@ -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;
}
}
}

View File

@@ -25,6 +25,7 @@ if(MARS_NWE_BUILD_NWFS_TESTS)
add_subdirectory(core/register)
add_subdirectory(core/schedule)
add_subdirectory(core/worktodo)
add_subdirectory(core/work)
add_subdirectory(core/alarm)
add_subdirectory(core/control)
add_subdirectory(core/asyncio)

View File

@@ -11,6 +11,7 @@ add_subdirectory(pssdebug)
add_subdirectory(register)
add_subdirectory(schedule)
add_subdirectory(worktodo)
add_subdirectory(work)
add_subdirectory(alarm)
add_subdirectory(control)
add_subdirectory(asyncio)

View File

@@ -0,0 +1,3 @@
add_executable(test_nwcore_work test_nwcore_work.c)
target_link_libraries(test_nwcore_work PRIVATE mars_nwe::core)
add_test(NAME nwcore.work COMMAND test_nwcore_work)

View File

@@ -0,0 +1,64 @@
#include <include/control.h>
#include <include/fsm.h>
#include <include/pssmpk.h>
#include <include/register.h>
#include <include/schedule.h>
#include <internal/pssConfig.h>
#include <stdio.h>
#include <stdlib.h>
#define CHECK(expr) do { \
if (!(expr)) { \
fprintf(stderr, "CHECK failed: %s:%d: %s\n", __FILE__, __LINE__, #expr); \
return EXIT_FAILURE; \
} \
} while (0)
extern STATUS WORK_Startup(void);
extern void WORK_Shutdown(void);
extern void WORK_Schedule(FsmLite_s *fsm, voidfunc_t action, ADDR parameter);
extern void WORK_Schedule_HIGH(FsmLite_s *fsm, voidfunc_t action, ADDR parameter);
extern void WORK_Schedule_LOW(FsmLite_s *fsm, voidfunc_t action, ADDR parameter);
extern NINT PendingWork;
typedef struct WorkTest_s {
int value;
} WorkTest_s;
static void work_action(FsmLite_s *fsm, ADDR parameter)
{
WorkTest_s *state = (WorkTest_s *)parameter;
if (fsm != NULL)
{
state->value++;
}
}
int main(void)
{
WorkTest_s state = {0};
FsmLite_s fsm;
FsmLite_s high;
FsmLite_s low;
configStartup();
nssInitializeSpinLockCode();
CHECK(COMN_RegisterLibraryResourceTags("nwcore.work") == zOK);
MPKNSS_LOCK();
CHECK(WORK_Startup() == zOK);
FSMLITE_INIT(&fsm, "work", 0);
FSMLITE_INIT(&high, "work-high", 1);
FSMLITE_INIT(&low, "work-low", 2);
WORK_Schedule(&fsm, (voidfunc_t)work_action, (ADDR)&state);
WORK_Schedule_HIGH(&high, (voidfunc_t)work_action, (ADDR)&state);
WORK_Schedule_LOW(&low, (voidfunc_t)work_action, (ADDR)&state);
CHECK(state.value == 3);
CHECK(PendingWork == 0);
WORK_Shutdown();
MPKNSS_UNLOCK();
return EXIT_SUCCESS;
}