|
Packit Service |
310c69 |
/*
|
|
Packit Service |
310c69 |
* Copyright (c) 2020 Red Hat, Inc.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* This program is free software; you can redistribute it and/or
|
|
Packit Service |
310c69 |
* modify it under the terms of the GNU General Public License
|
|
Packit Service |
310c69 |
* as published by the Free Software Foundation; either version 2
|
|
Packit Service |
310c69 |
* of the License, or (at your option) any later version.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* This program is distributed in the hope that it will be useful,
|
|
Packit Service |
310c69 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
310c69 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit Service |
310c69 |
* GNU General Public License for more details.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* You should have received a copy of the GNU General Public License
|
|
Packit Service |
310c69 |
* along with this program; if not, write to the Free Software
|
|
Packit Service |
310c69 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
Packit Service |
310c69 |
* 02110-1301, USA.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* $Id: //eng/vdo-releases/aluminum/src/c++/vdo/base/actionManager.c#9 $
|
|
Packit Service |
310c69 |
*/
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
#include "actionManager.h"
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
#include "memoryAlloc.h"
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
#include "adminState.h"
|
|
Packit Service |
310c69 |
#include "completion.h"
|
|
Packit Service |
310c69 |
#include "types.h"
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/** An action to be performed in each of a set of zones */
|
|
Packit Service |
310c69 |
typedef struct action Action;
|
|
Packit Service |
310c69 |
struct action {
|
|
Packit Service |
310c69 |
/** Whether this structure is in use */
|
|
Packit Service |
310c69 |
bool inUse;
|
|
Packit Service |
310c69 |
/** The admin operation associated with this action */
|
|
Packit Service |
310c69 |
AdminStateCode operation;
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* The method to run on the initiator thread before the action is applied to
|
|
Packit Service |
310c69 |
* each zone.
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
ActionPreamble *preamble;
|
|
Packit Service |
310c69 |
/** The action to be performed in each zone */
|
|
Packit Service |
310c69 |
ZoneAction *zoneAction;
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* The method to run on the initiator thread after the action has been
|
|
Packit Service |
310c69 |
* applied to each zone
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
ActionConclusion *conclusion;
|
|
Packit Service |
310c69 |
/** The object to notify when the action is complete */
|
|
Packit Service |
310c69 |
VDOCompletion *parent;
|
|
Packit Service |
310c69 |
/** The action specific context */
|
|
Packit Service |
310c69 |
void *context;
|
|
Packit Service |
310c69 |
/** The action to perform after this one */
|
|
Packit Service |
310c69 |
Action *next;
|
|
Packit Service |
310c69 |
};
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
struct actionManager {
|
|
Packit Service |
310c69 |
/** The completion for performing actions */
|
|
Packit Service |
310c69 |
VDOCompletion completion;
|
|
Packit Service |
310c69 |
/** The state of this action manager */
|
|
Packit Service |
310c69 |
AdminState state;
|
|
Packit Service |
310c69 |
/** The two action slots*/
|
|
Packit Service |
310c69 |
Action actions[2];
|
|
Packit Service |
310c69 |
/** The current action slot */
|
|
Packit Service |
310c69 |
Action *currentAction;
|
|
Packit Service |
310c69 |
/** The number of zones in which an action is to be applied */
|
|
Packit Service |
310c69 |
ZoneCount zones;
|
|
Packit Service |
310c69 |
/** A function to schedule a default next action */
|
|
Packit Service |
310c69 |
ActionScheduler *scheduler;
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* A function to get the id of the thread on which to apply an action to a
|
|
Packit Service |
310c69 |
* zone
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
ZoneThreadGetter *getZoneThreadID;
|
|
Packit Service |
310c69 |
/** The ID of the thread on which actions may be initiated */
|
|
Packit Service |
310c69 |
ThreadID initiatorThreadID;
|
|
Packit Service |
310c69 |
/** Opaque data associated with this action manager */
|
|
Packit Service |
310c69 |
void *context;
|
|
Packit Service |
310c69 |
/** The zone currently being acted upon */
|
|
Packit Service |
310c69 |
ZoneCount actingZone;
|
|
Packit Service |
310c69 |
};
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Convert a generic VDOCompletion to a ActionManager.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @param completion The completion to convert
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @return The completion as a ActionManager
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static inline ActionManager *asActionManager(VDOCompletion *completion)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
STATIC_ASSERT(offsetof(ActionManager, completion) == 0);
|
|
Packit Service |
310c69 |
assertCompletionType(completion->type, ACTION_COMPLETION);
|
|
Packit Service |
310c69 |
return (ActionManager *) completion;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* An action scheduler which does not schedule an action.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* Implements ActionScheduler.
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static bool noDefaultAction(void *context __attribute__((unused)))
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return false;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* A default preamble which does nothing.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* Implements ActionPreamble
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static void noPreamble(void *context __attribute__((unused)),
|
|
Packit Service |
310c69 |
VDOCompletion *completion)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
completeCompletion(completion);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* A default conclusion which does nothing.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* Implements ActionConclusion.
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static int noConclusion(void *context __attribute__((unused))) {
|
|
Packit Service |
310c69 |
return VDO_SUCCESS;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
int makeActionManager(ZoneCount zones,
|
|
Packit Service |
310c69 |
ZoneThreadGetter *getZoneThreadID,
|
|
Packit Service |
310c69 |
ThreadID initiatorThreadID,
|
|
Packit Service |
310c69 |
void *context,
|
|
Packit Service |
310c69 |
ActionScheduler *scheduler,
|
|
Packit Service |
310c69 |
PhysicalLayer *layer,
|
|
Packit Service |
310c69 |
ActionManager **managerPtr)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
ActionManager *manager;
|
|
Packit Service |
310c69 |
int result = ALLOCATE(1, ActionManager, __func__, &manager);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
*manager = (ActionManager) {
|
|
Packit Service |
310c69 |
.zones = zones,
|
|
Packit Service |
310c69 |
.scheduler = ((scheduler == NULL) ? noDefaultAction : scheduler),
|
|
Packit Service |
310c69 |
.getZoneThreadID = getZoneThreadID,
|
|
Packit Service |
310c69 |
.initiatorThreadID = initiatorThreadID,
|
|
Packit Service |
310c69 |
.context = context,
|
|
Packit Service |
310c69 |
};
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
manager->actions[0].next = &manager->actions[1];
|
|
Packit Service |
310c69 |
manager->currentAction = manager->actions[1].next = &manager->actions[0];
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
result = initializeEnqueueableCompletion(&manager->completion,
|
|
Packit Service |
310c69 |
ACTION_COMPLETION, layer);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
freeActionManager(&manager);
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
*managerPtr = manager;
|
|
Packit Service |
310c69 |
return VDO_SUCCESS;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
void freeActionManager(ActionManager **managerPtr)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
ActionManager *manager = *managerPtr;
|
|
Packit Service |
310c69 |
if (manager == NULL) {
|
|
Packit Service |
310c69 |
return;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
destroyEnqueueable(&manager->completion);
|
|
Packit Service |
310c69 |
FREE(manager);
|
|
Packit Service |
310c69 |
*managerPtr = NULL;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
AdminStateCode getCurrentManagerOperation(ActionManager *manager)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return manager->state.state;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
void *getCurrentActionContext(ActionManager *manager)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return (manager->currentAction->inUse
|
|
Packit Service |
310c69 |
? manager->currentAction->context : NULL);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
static void finishActionCallback(VDOCompletion *completion);
|
|
Packit Service |
310c69 |
static void applyToZone(VDOCompletion *completion);
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Get the thread ID for the current zone.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @param manager The action manager
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @return The ID of the thread on which to run actions for the current zone
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static ThreadID getActingZoneThreadID(ActionManager *manager)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return manager->getZoneThreadID(manager->context, manager->actingZone);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Prepare the manager's completion to run on the next zone.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @param manager The action manager
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static void prepareForNextZone(ActionManager *manager)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
prepareForRequeue(&manager->completion, applyToZone,
|
|
Packit Service |
310c69 |
preserveErrorAndContinue, getActingZoneThreadID(manager),
|
|
Packit Service |
310c69 |
manager->currentAction->parent);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Prepare the manager's completion to run the conclusion on the initiator
|
|
Packit Service |
310c69 |
* thread.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @param manager The action manager
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static void prepareForConclusion(ActionManager *manager)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
prepareForRequeue(&manager->completion, finishActionCallback,
|
|
Packit Service |
310c69 |
preserveErrorAndContinue, manager->initiatorThreadID,
|
|
Packit Service |
310c69 |
manager->currentAction->parent);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Perform an action on the next zone if there is one.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @param completion The action completion
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static void applyToZone(VDOCompletion *completion)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
ActionManager *manager = asActionManager(completion);
|
|
Packit Service |
310c69 |
ASSERT_LOG_ONLY((getCallbackThreadID() == getActingZoneThreadID(manager)),
|
|
Packit Service |
310c69 |
"applyToZone() called on acting zones's thread");
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
ZoneCount zone = manager->actingZone++;
|
|
Packit Service |
310c69 |
if (manager->actingZone == manager->zones) {
|
|
Packit Service |
310c69 |
// We are about to apply to the last zone. Once that is finished,
|
|
Packit Service |
310c69 |
// we're done, so go back to the initiator thread and finish up.
|
|
Packit Service |
310c69 |
prepareForConclusion(manager);
|
|
Packit Service |
310c69 |
} else {
|
|
Packit Service |
310c69 |
// Prepare to come back on the next zone
|
|
Packit Service |
310c69 |
prepareForNextZone(manager);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
manager->currentAction->zoneAction(manager->context, zone, completion);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* The error handler for preamble errors.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @param completion The manager completion
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static void handlePreambleError(VDOCompletion *completion)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
// Skip the zone actions since the preamble failed.
|
|
Packit Service |
310c69 |
completion->callback = finishActionCallback;
|
|
Packit Service |
310c69 |
preserveErrorAndContinue(completion);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Launch the current action.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @param manager The action manager
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static void launchCurrentAction(ActionManager *manager)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
Action *action = manager->currentAction;
|
|
Packit Service |
310c69 |
int result = startOperation(&manager->state, action->operation);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
if (action->parent != NULL) {
|
|
Packit Service |
310c69 |
setCompletionResult(action->parent, result);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
// We aren't going to run the preamble, so don't run the conclusion
|
|
Packit Service |
310c69 |
action->conclusion = noConclusion;
|
|
Packit Service |
310c69 |
finishActionCallback(&manager->completion);
|
|
Packit Service |
310c69 |
return;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
if (action->zoneAction == NULL) {
|
|
Packit Service |
310c69 |
prepareForConclusion(manager);
|
|
Packit Service |
310c69 |
} else {
|
|
Packit Service |
310c69 |
manager->actingZone = 0;
|
|
Packit Service |
310c69 |
prepareForRequeue(&manager->completion, applyToZone, handlePreambleError,
|
|
Packit Service |
310c69 |
getActingZoneThreadID(manager),
|
|
Packit Service |
310c69 |
manager->currentAction->parent);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
action->preamble(manager->context, &manager->completion);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
bool scheduleDefaultAction(ActionManager *manager)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
// Don't schedule a default action if we are operating or not in normal
|
|
Packit Service |
310c69 |
// operation.
|
|
Packit Service |
310c69 |
return ((manager->state.state == ADMIN_STATE_NORMAL_OPERATION)
|
|
Packit Service |
310c69 |
&& manager->scheduler(manager->context));
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Finish an action now that it has been applied to all zones. This
|
|
Packit Service |
310c69 |
* callback is registered in applyToZone().
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @param completion The action manager completion
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static void finishActionCallback(VDOCompletion *completion)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
ActionManager *manager = asActionManager(completion);
|
|
Packit Service |
310c69 |
Action action = *(manager->currentAction);
|
|
Packit Service |
310c69 |
manager->currentAction->inUse = false;
|
|
Packit Service |
310c69 |
manager->currentAction = manager->currentAction->next;
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
// We need to check this now to avoid use-after-free issues if running the
|
|
Packit Service |
310c69 |
// conclusion or notifying the parent results in the manager being freed.
|
|
Packit Service |
310c69 |
bool hasNextAction = (manager->currentAction->inUse
|
|
Packit Service |
310c69 |
|| scheduleDefaultAction(manager));
|
|
Packit Service |
310c69 |
int result = action.conclusion(manager->context);
|
|
Packit Service |
310c69 |
finishOperation(&manager->state);
|
|
Packit Service |
310c69 |
if (action.parent != NULL) {
|
|
Packit Service |
310c69 |
finishCompletion(action.parent, result);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
if (hasNextAction) {
|
|
Packit Service |
310c69 |
launchCurrentAction(manager);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
bool scheduleAction(ActionManager *manager,
|
|
Packit Service |
310c69 |
ActionPreamble *preamble,
|
|
Packit Service |
310c69 |
ZoneAction *zoneAction,
|
|
Packit Service |
310c69 |
ActionConclusion *conclusion,
|
|
Packit Service |
310c69 |
VDOCompletion *parent)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return scheduleOperation(manager, ADMIN_STATE_OPERATING, preamble,
|
|
Packit Service |
310c69 |
zoneAction, conclusion, parent);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
bool scheduleOperation(ActionManager *manager,
|
|
Packit Service |
310c69 |
AdminStateCode operation,
|
|
Packit Service |
310c69 |
ActionPreamble *preamble,
|
|
Packit Service |
310c69 |
ZoneAction *zoneAction,
|
|
Packit Service |
310c69 |
ActionConclusion *conclusion,
|
|
Packit Service |
310c69 |
VDOCompletion *parent)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return scheduleOperationWithContext(manager, operation, preamble, zoneAction,
|
|
Packit Service |
310c69 |
conclusion, NULL, parent);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
bool scheduleOperationWithContext(ActionManager *manager,
|
|
Packit Service |
310c69 |
AdminStateCode operation,
|
|
Packit Service |
310c69 |
ActionPreamble *preamble,
|
|
Packit Service |
310c69 |
ZoneAction *zoneAction,
|
|
Packit Service |
310c69 |
ActionConclusion *conclusion,
|
|
Packit Service |
310c69 |
void *context,
|
|
Packit Service |
310c69 |
VDOCompletion *parent)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
ASSERT_LOG_ONLY((getCallbackThreadID() == manager->initiatorThreadID),
|
|
Packit Service |
310c69 |
"action initiated from correct thread");
|
|
Packit Service |
310c69 |
Action *action;
|
|
Packit Service |
310c69 |
if (!manager->currentAction->inUse) {
|
|
Packit Service |
310c69 |
action = manager->currentAction;
|
|
Packit Service |
310c69 |
} else if (!manager->currentAction->next->inUse) {
|
|
Packit Service |
310c69 |
action = manager->currentAction->next;
|
|
Packit Service |
310c69 |
} else {
|
|
Packit Service |
310c69 |
if (parent != NULL) {
|
|
Packit Service |
310c69 |
finishCompletion(parent, VDO_COMPONENT_BUSY);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
return false;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
*action = (Action) {
|
|
Packit Service |
310c69 |
.inUse = true,
|
|
Packit Service |
310c69 |
.operation = operation,
|
|
Packit Service |
310c69 |
.preamble = (preamble == NULL) ? noPreamble : preamble,
|
|
Packit Service |
310c69 |
.zoneAction = zoneAction,
|
|
Packit Service |
310c69 |
.conclusion = (conclusion == NULL) ? noConclusion : conclusion,
|
|
Packit Service |
310c69 |
.context = context,
|
|
Packit Service |
310c69 |
.parent = parent,
|
|
Packit Service |
310c69 |
.next = action->next,
|
|
Packit Service |
310c69 |
};
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
if (action == manager->currentAction) {
|
|
Packit Service |
310c69 |
launchCurrentAction(manager);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
return true;
|
|
Packit Service |
310c69 |
}
|