/* * Copyright (c) 2020 Red Hat, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. * * $Id: //eng/vdo-releases/aluminum/src/c++/vdo/base/completion.h#11 $ */ #ifndef COMPLETION_H #define COMPLETION_H #include "permassert.h" #include "physicalLayer.h" #include "ringNode.h" #include "types.h" typedef enum __attribute__((packed)) { // Keep UNSET_COMPLETION_TYPE at the top. UNSET_COMPLETION_TYPE = 0, // Keep the rest of these in sorted order. If you add or remove an entry, // be sure to update the corresponding list in completion.c. ACTION_COMPLETION, ADMIN_COMPLETION, ASYNC_ACTION_CONTEXT, BLOCK_ALLOCATOR_COMPLETION, BLOCK_MAP_RECOVERY_COMPLETION, CHECK_IDENTIFIER_COMPLETION, EXTERNAL_COMPLETION, FLUSH_NOTIFICATION_COMPLETION, GENERATION_FLUSHED_COMPLETION, HEARTBEAT_COMPLETION, LOCK_COUNTER_COMPLETION, PARTITION_COPY_COMPLETION, READ_ONLY_MODE_COMPLETION, READ_ONLY_REBUILD_COMPLETION, RECOVERY_COMPLETION, REFERENCE_COUNT_REBUILD_COMPLETION, SLAB_SCRUBBER_COMPLETION, SUB_TASK_COMPLETION, TEST_COMPLETION, // each unit test may define its own VDO_COMMAND_COMPLETION, VDO_COMMAND_SUB_COMPLETION, VDO_EXTENT_COMPLETION, VDO_PAGE_COMPLETION, VIO_COMPLETION, WRAPPING_COMPLETION, // Keep MAX_COMPLETION_TYPE at the bottom. MAX_COMPLETION_TYPE } VDOCompletionType; /** * An asynchronous VDO operation. * * @param completion the completion of the operation **/ typedef void VDOAction(VDOCompletion *completion); struct vdoCompletion { /** The type of completion this is */ VDOCompletionType type; /** * true once the processing of the operation is complete. * This flag should not be used by waiters external to the VDO base as * it is used to gate calling the callback. **/ bool complete; /** * If true, queue this completion on the next callback invocation, even if * it is already running on the correct thread. **/ bool requeue; /** The ID of the thread which should run the next callback */ ThreadID callbackThreadID; /** The result of the operation */ int result; /** The physical layer on which this completion operates */ PhysicalLayer *layer; /** The callback which will be called once the operation is complete */ VDOAction *callback; /** The callback which, if set, will be called if an error result is set */ VDOAction *errorHandler; /** The parent object, if any, that spawned this completion */ void *parent; /** The enqueueable for this completion (may be NULL) */ Enqueueable *enqueueable; }; /** * Actually run the callback. This function must be called from the correct * callback thread. **/ static inline void runCallback(VDOCompletion *completion) { if ((completion->result != VDO_SUCCESS) && (completion->errorHandler != NULL)) { completion->errorHandler(completion); return; } completion->callback(completion); } /** * Set the result of a completion. Older errors will not be masked. * * @param completion The completion whose result is to be set * @param result The result to set **/ void setCompletionResult(VDOCompletion *completion, int result); /** * Initialize a completion to a clean state, for reused completions. * * @param completion The completion to initialize * @param type The type of the completion * @param layer The physical layer of the completion **/ void initializeCompletion(VDOCompletion *completion, VDOCompletionType type, PhysicalLayer *layer); /** * Initialize a completion to a clean state and make an enqueueable for it. * * @param completion The completion to initialize * @param type The type of the completion * @param layer The physical layer of the completion * * @return VDO_SUCCESS or an error **/ int initializeEnqueueableCompletion(VDOCompletion *completion, VDOCompletionType type, PhysicalLayer *layer) __attribute__((warn_unused_result)); /** * Reset a completion to a clean state, while keeping * the type, layer and parent information. * * @param completion the completion to reset **/ void resetCompletion(VDOCompletion *completion); /** * Invoke the callback of a completion. If called on the correct thread (i.e. * the one specified in the completion's callbackThreadID field), the * completion will be run immediately. Otherwise, the completion will be * enqueued on the correct callback thread. **/ void invokeCallback(VDOCompletion *completion); /** * Continue processing a completion by setting the current result and calling * invokeCallback(). * * @param completion The completion to continue * @param result The current result (will not mask older errors) **/ void continueCompletion(VDOCompletion *completion, int result); /** * Complete a completion. * * @param completion The completion to complete **/ void completeCompletion(VDOCompletion *completion); /** * Finish a completion. * * @param completion The completion to finish * @param result The result of the completion (will not mask older errors) **/ static inline void finishCompletion(VDOCompletion *completion, int result) { setCompletionResult(completion, result); completeCompletion(completion); } /** * Complete a completion and NULL out the reference to it. * * @param completionPtr A pointer to the completion to release **/ void releaseCompletion(VDOCompletion **completionPtr); /** * Finish a completion and NULL out the reference to it. * * @param completionPtr A pointer to the completion to release * @param result The result of the completion **/ void releaseCompletionWithResult(VDOCompletion **completionPtr, int result); /** * A callback to finish the parent of a completion. * * @param completion The completion which has finished and whose parent should * be finished **/ void finishParentCallback(VDOCompletion *completion); /** * Error handler which preserves an error in the parent (if there is one), * and then resets the failing completion and calls its non-error callback. * * @param completion The completion which failed **/ void preserveErrorAndContinue(VDOCompletion *completion); /** * A callback which does nothing. This callback is intended to be set as an * error handler in the case where an error should do nothing. * * @param completion The completion being called back **/ static inline void noopCallback(VDOCompletion *completion __attribute__((unused))) { } /** * Destroy the enqueueable associated with this completion. * * @param completion The completion **/ void destroyEnqueueable(VDOCompletion *completion); /** * Assert that a completion is of the correct type * * @param actual The actual completion type * @param expected The expected completion type * * @return VDO_SUCCESS or VDO_PARAMETER_MISMATCH **/ int assertCompletionType(VDOCompletionType actual, VDOCompletionType expected); /** * Return the name of a completion type. * * @param completionType the completion type * * @return a pointer to a static string; if the completionType is unknown * this is to a static buffer that may be overwritten. **/ const char *getCompletionTypeName(VDOCompletionType completionType); /** * Set the callback for a completion. * * @param completion The completion * @param callback The callback to register * @param threadID The ID of the thread on which the callback should run **/ static inline void setCallback(VDOCompletion *completion, VDOAction *callback, ThreadID threadID) { completion->callback = callback; completion->callbackThreadID = threadID; } /** * Set the callback for a completion and invoke it immediately. * * @param completion The completion * @param callback The callback to register * @param threadID The ID of the thread on which the callback should run **/ static inline void launchCallback(VDOCompletion *completion, VDOAction *callback, ThreadID threadID) { setCallback(completion, callback, threadID); invokeCallback(completion); } /** * Set the callback and parent for a completion. * * @param completion The completion * @param callback The callback to register * @param threadID The ID of the thread on which the callback should run * @param parent The new parent of the completion **/ static inline void setCallbackWithParent(VDOCompletion *completion, VDOAction *callback, ThreadID threadID, void *parent) { setCallback(completion, callback, threadID); completion->parent = parent; } /** * Set the callback and parent for a completion and invoke the callback * immediately. * * @param completion The completion * @param callback The callback to register * @param threadID The ID of the thread on which the callback should run * @param parent The new parent of the completion **/ static inline void launchCallbackWithParent(VDOCompletion *completion, VDOAction *callback, ThreadID threadID, void *parent) { setCallbackWithParent(completion, callback, threadID, parent); invokeCallback(completion); } /** * Prepare a completion for launch. Reset it, and then set its callback, error * handler, callback thread, and parent. * * @param completion The completion * @param callback The callback to register * @param errorHandler The error handler to register * @param threadID The ID of the thread on which the callback should run * @param parent The new parent of the completion **/ static inline void prepareCompletion(VDOCompletion *completion, VDOAction *callback, VDOAction *errorHandler, ThreadID threadID, void *parent) { resetCompletion(completion); setCallbackWithParent(completion, callback, threadID, parent); completion->errorHandler = errorHandler; } /** * Prepare a completion for launch ensuring that it will always be requeued. * Reset it, and then set its callback, error handler, callback thread, and * parent. * * @param completion The completion * @param callback The callback to register * @param errorHandler The error handler to register * @param threadID The ID of the thread on which the callback should run * @param parent The new parent of the completion **/ static inline void prepareForRequeue(VDOCompletion *completion, VDOAction *callback, VDOAction *errorHandler, ThreadID threadID, void *parent) { prepareCompletion(completion, callback, errorHandler, threadID, parent); completion->requeue = true; } /** * Prepare a completion for launch which will complete its parent when * finished. * * @param completion The completion * @param parent The parent to complete **/ static inline void prepareToFinishParent(VDOCompletion *completion, VDOCompletion *parent) { prepareCompletion(completion, finishParentCallback, finishParentCallback, parent->callbackThreadID, parent); } #endif // COMPLETION_H