windows-nt/Source/XPSP1/NT/ds/netapi/svcdlls/upssvc/upsexe/statmach.c
2020-09-26 16:20:57 +08:00

321 lines
6.5 KiB
C

/* Copyright 1999 American Power Conversion, All Rights Reserved
*
* Description:
* Implements the native UPS sevice state machine. The various states executed
* within the state machine are housed in separate files.
*
* Revision History:
* dsmith 31Mar1999 Created
*
*/
#include <windows.h>
#include "states.h"
#include "events.h"
#include "driver.h"
#include "running_statmach.h"
#include "upsreg.h"
// Internal function Prototypes
static void enter_state(DWORD aNewState, DWORD anEvent);
static DWORD do_work(DWORD aCurrentState);
static void exit_state(DWORD anOldState, DWORD anEvent);
static DWORD change_state(DWORD aCurrentState, DWORD anEvent);
static DWORD get_new_state(DWORD aCurrentState, DWORD anEvent);
// State Machine Variables
BOOL theIsStateMachineActive = TRUE;
/**
* RunStateMachine
*
* Description:
* Starts the state machine. This method will not return until the state machine
* exits.
*
* Parameters:
* None
*
* Returns:
* None
*/
void RunStateMachine(){
// Set the primary state to RUNNING
DWORD new_state = RUNNING;
DWORD current_state = new_state;
DWORD event = NO_EVENT;
enter_state(new_state, event);
// Continue processing state changes until the state becomes the EXIT_NOW state
while (new_state != EXIT_NOW){
current_state = new_state;
event = do_work(current_state);
new_state = change_state(new_state, event);
}
}
/**
* StopStateMachine
*
* Description:
* Stops the UPS service state machine if the service is not in the
* middle of a shutdown sequence.
*
* Parameters:
* None
*
* Returns:
* None
*/
void StopStateMachine(){
theIsStateMachineActive = FALSE;
// Wake up the main service thread
UPSCancelWait();
}
/**
* IsStateMachineActive
*
* Description:
* Returns the running status of the state machine. If the state machine
* has been commanded to exit, then the status will be FALSE, otherwise,
* this method will return true.
*
* Parameters:
* None
*
* Returns:
* TRUE if the state machine is active
* FALSE if the state machine is not active
*/
BOOL IsStateMachineActive(){
return theIsStateMachineActive;
}
/**
* change_state
*
* Description:
* Determines what the new state should be based upon the input parameters.
* The current state is exited and the new state is initialized.
*
* Parameters:
* anEvent The event that is causing the state transition.
* aCurrentState The state before the transition.
*
* Returns:
* The new state.
*/
DWORD change_state(DWORD aCurrentState, DWORD anEvent){
DWORD new_state;
new_state = get_new_state(aCurrentState, anEvent);
if (new_state != aCurrentState){
exit_state(aCurrentState, anEvent);
enter_state(new_state, anEvent);
}
return new_state;
}
/**
* get_new_state
*
* Description:
* Determines what the new state should be based upon the input parameters
* and registry entries.
*
* Parameters:
* anEvent The event that is causing the state transition.
* aCurrentState The state before the transition.
*
* Returns:
* The new state.
*/
static DWORD get_new_state(DWORD aCurrentState, DWORD anEvent){
DWORD new_state;
switch (anEvent){
case INITIALIZATION_COMPLETE:
new_state = RUNNING;
break;
case LOST_COMM:
case LOW_BATTERY:
case ON_BATTERY_TIMER_EXPIRED:
{
DWORD shutdown_behavior = UPS_SHUTDOWN_SHUTDOWN;
// Check the registry to determine if we shutdown or hibernate
InitUPSConfigBlock();
if ((GetUPSConfigCriticalPowerAction(&shutdown_behavior) == ERROR_SUCCESS)
&& (shutdown_behavior == UPS_SHUTDOWN_HIBERNATE)) {
// Hibernate was selected as the CriticalPowerAction
new_state = HIBERNATE;
}
else {
// Shutdown was selected as the CriticalPowerAction
new_state = WAITING_TO_SHUTDOWN;
}
// Free the UPS registry config block
FreeUPSConfigBlock();
}
break;
case SHUTDOWN_ACTIONS_COMPLETED:
new_state = SHUTTING_DOWN;
break;
case SHUTDOWN_COMPLETE:
new_state = STOPPING;
break;
case STOPPED:
new_state = EXIT_NOW;
break;
case RETURN_FROM_HIBERNATION:
new_state = INITIALIZING;
break;
case HIBERNATION_ERROR:
new_state = SHUTTING_DOWN;
break;
default:
new_state = aCurrentState;
}
// If the state machine has been commanded to exit, then return the
// stopping state
if (IsStateMachineActive() == FALSE){
// Ignore this condition if the transition is into the shutting down state
// Shutdowns in progress cannot be interrupted.
if (new_state != SHUTTING_DOWN && new_state != EXIT_NOW){
new_state = STOPPING;
}
}
return new_state;
}
/**
* enter_state
*
* Description:
* Initializes the new state.
*
* Parameters:
* anEvent The event that is causing the transition to a new state.
* aNewState The state to enter.
*
* Returns:
* None
*/
static void enter_state(DWORD aNewState, DWORD anEvent){
switch (aNewState){
case INITIALIZING:
Initializing_Enter(anEvent);
break;
case RUNNING:
Running_Enter(anEvent);
break;
case WAITING_TO_SHUTDOWN:
WaitingToShutdown_Enter(anEvent);
break;
case SHUTTING_DOWN:
ShuttingDown_Enter(anEvent);
break;
case HIBERNATE:
Hibernate_Enter(anEvent);
break;
case STOPPING:
Stopping_Enter(anEvent);
break;
default:
break;
}
}
/**
* do_work
*
* Description:
* Transfers control to a state.
*
* Parameters:
* aCurrentState The state to perform the work in.
*
* Returns:
* The event that caused the transition from one of the states
*/
static DWORD do_work(DWORD aCurrentState){
DWORD event = NO_EVENT;
switch (aCurrentState){
case INITIALIZING:
event = Initializing_DoWork();
break;
case RUNNING:
event = Running_DoWork();
break;
case WAITING_TO_SHUTDOWN:
event = WaitingToShutdown_DoWork();
break;
case SHUTTING_DOWN:
event = ShuttingDown_DoWork();
break;
case HIBERNATE:
event = Hibernate_DoWork();
break;
case STOPPING:
event = Stopping_DoWork();
break;
default:
break;
}
return event;
}
/**
* exit_state
*
* Description:
* Exits the currently executing state.
*
* Parameters:
* anEvent The event that is causing the transition from the state.
* anOldState The current state.
*
* Returns:
* None
*/
static void exit_state(DWORD anOldState, DWORD anEvent){
switch (anOldState){
case INITIALIZING:
Initializing_Exit(anEvent);
break;
case RUNNING:
Running_Exit(anEvent);
break;
case WAITING_TO_SHUTDOWN:
WaitingToShutdown_Exit(anEvent);
break;
case SHUTTING_DOWN:
ShuttingDown_Exit(anEvent);
break;
case HIBERNATE:
Hibernate_Exit(anEvent);
break;
case STOPPING:
Stopping_Exit(anEvent);
break;
default:
break;
}
}