|
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/readOnlyNotifier.c#5 $
|
|
Packit Service |
310c69 |
*/
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
#include "readOnlyNotifier.h"
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
#include "atomic.h"
|
|
Packit Service |
310c69 |
#include "logger.h"
|
|
Packit Service |
310c69 |
#include "memoryAlloc.h"
|
|
Packit Service |
310c69 |
#include "permassert.h"
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
#include "completion.h"
|
|
Packit Service |
310c69 |
#include "physicalLayer.h"
|
|
Packit Service |
310c69 |
#include "threadConfig.h"
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* A ReadOnlyNotifier has a single completion which is used to perform
|
|
Packit Service |
310c69 |
* read-only notifications, however, enterReadOnlyMode() may be called from any
|
|
Packit Service |
310c69 |
* base thread. A pair of atomic fields are used to control the read-only mode
|
|
Packit Service |
310c69 |
* entry process. The first field holds the read-only error. The second is the
|
|
Packit Service |
310c69 |
* state field, which may hold any of the four special values enumerated here.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* When enterReadOnlyMode() is called from some base thread, a compare-and-swap
|
|
Packit Service |
310c69 |
* is done on the readOnlyError, setting it to the supplied error if the value
|
|
Packit Service |
310c69 |
* was VDO_SUCCESS. If this fails, some other thread has already intiated
|
|
Packit Service |
310c69 |
* read-only entry or scheduled a pending entry, so the call exits. Otherwise,
|
|
Packit Service |
310c69 |
* a compare-and-swap is done on the state, setting it to NOTIFYING if the
|
|
Packit Service |
310c69 |
* value was MAY_NOTIFY. If this succeeds, the caller initiates the
|
|
Packit Service |
310c69 |
* notification. If this failed due to notifications being disallowed, the
|
|
Packit Service |
310c69 |
* notifier will be in the MAY_NOT_NOTIFY state but readOnlyError will not be
|
|
Packit Service |
310c69 |
* VDO_SUCCESS. This configuration will indicate to allowReadOnlyModeEntry()
|
|
Packit Service |
310c69 |
* that there is a pending notification to perform.
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
enum {
|
|
Packit Service |
310c69 |
/** Notifications are allowed but not in progress */
|
|
Packit Service |
310c69 |
MAY_NOTIFY = 0,
|
|
Packit Service |
310c69 |
/** A notification is in progress */
|
|
Packit Service |
310c69 |
NOTIFYING,
|
|
Packit Service |
310c69 |
/** Notifications are not allowed */
|
|
Packit Service |
310c69 |
MAY_NOT_NOTIFY,
|
|
Packit Service |
310c69 |
/** A notification has completed */
|
|
Packit Service |
310c69 |
NOTIFIED,
|
|
Packit Service |
310c69 |
};
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* An object to be notified when the VDO enters read-only mode
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
typedef struct readOnlyListener ReadOnlyListener;
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
struct readOnlyListener {
|
|
Packit Service |
310c69 |
/** The listener */
|
|
Packit Service |
310c69 |
void *listener;
|
|
Packit Service |
310c69 |
/** The method to call to notifiy the listener */
|
|
Packit Service |
310c69 |
ReadOnlyNotification *notify;
|
|
Packit Service |
310c69 |
/** A pointer to the next listener */
|
|
Packit Service |
310c69 |
ReadOnlyListener *next;
|
|
Packit Service |
310c69 |
};
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Data associated with each base code thread.
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
typedef struct threadData {
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Each thread maintains its own notion of whether the VDO is read-only so
|
|
Packit Service |
310c69 |
* that the read-only state can be checked from any base thread without
|
|
Packit Service |
310c69 |
* worrying about synchronization or thread safety. This does mean that
|
|
Packit Service |
310c69 |
* knowledge of the VDO going read-only does not occur simultaneously across
|
|
Packit Service |
310c69 |
* the VDO's threads, but that does not seem to cause any problems.
|
|
Packit Service |
310c69 |
*/
|
|
Packit Service |
310c69 |
bool isReadOnly;
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* A list of objects waiting to be notified on this thread that the VDO has
|
|
Packit Service |
310c69 |
* entered read-only mode.
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
ReadOnlyListener *listeners;
|
|
Packit Service |
310c69 |
} ThreadData;
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
struct readOnlyNotifier {
|
|
Packit Service |
310c69 |
/** The completion for entering read-only mode */
|
|
Packit Service |
310c69 |
VDOCompletion completion;
|
|
Packit Service |
310c69 |
/** A completion waiting for notifications to be drained or enabled */
|
|
Packit Service |
310c69 |
VDOCompletion *waiter;
|
|
Packit Service |
310c69 |
/** The code of the error which put the VDO into read-only mode */
|
|
Packit Service |
310c69 |
Atomic32 readOnlyError;
|
|
Packit Service |
310c69 |
/** The current state of the notifier (values described above) */
|
|
Packit Service |
310c69 |
Atomic32 state;
|
|
Packit Service |
310c69 |
/** The thread config of the VDO */
|
|
Packit Service |
310c69 |
const ThreadConfig *threadConfig;
|
|
Packit Service |
310c69 |
/** The array of per-thread data */
|
|
Packit Service |
310c69 |
ThreadData threadData[];
|
|
Packit Service |
310c69 |
};
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Convert a generic VDOCompletion to a ReadOnlyNotifier.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @param completion The completion to convert
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @return The completion as a ReadOnlyNotifier
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static inline ReadOnlyNotifier *asNotifier(VDOCompletion *completion)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
STATIC_ASSERT(offsetof(ReadOnlyNotifier, completion) == 0);
|
|
Packit Service |
310c69 |
assertCompletionType(completion->type, READ_ONLY_MODE_COMPLETION);
|
|
Packit Service |
310c69 |
return (ReadOnlyNotifier *) completion;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
int makeReadOnlyNotifier(bool isReadOnly,
|
|
Packit Service |
310c69 |
const ThreadConfig *threadConfig,
|
|
Packit Service |
310c69 |
PhysicalLayer *layer,
|
|
Packit Service |
310c69 |
ReadOnlyNotifier **notifierPtr)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
ReadOnlyNotifier *notifier;
|
|
Packit Service |
310c69 |
int result = ALLOCATE_EXTENDED(ReadOnlyNotifier,
|
|
Packit Service |
310c69 |
threadConfig->baseThreadCount, ThreadData,
|
|
Packit Service |
310c69 |
__func__, ¬ifier);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
notifier->threadConfig = threadConfig;
|
|
Packit Service |
310c69 |
if (isReadOnly) {
|
|
Packit Service |
310c69 |
atomicStore32(¬ifier->readOnlyError, (uint32_t) VDO_READ_ONLY);
|
|
Packit Service |
310c69 |
atomicStore32(¬ifier->state, NOTIFIED);
|
|
Packit Service |
310c69 |
} else {
|
|
Packit Service |
310c69 |
atomicStore32(¬ifier->state, MAY_NOTIFY);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
result = initializeEnqueueableCompletion(¬ifier->completion,
|
|
Packit Service |
310c69 |
READ_ONLY_MODE_COMPLETION, layer);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
freeReadOnlyNotifier(¬ifier);
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
for (ThreadCount id = 0; id < threadConfig->baseThreadCount; id++) {
|
|
Packit Service |
310c69 |
notifier->threadData[id].isReadOnly = isReadOnly;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
*notifierPtr = notifier;
|
|
Packit Service |
310c69 |
return VDO_SUCCESS;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
void freeReadOnlyNotifier(ReadOnlyNotifier **notifierPtr)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
ReadOnlyNotifier *notifier = *notifierPtr;
|
|
Packit Service |
310c69 |
if (notifier == NULL) {
|
|
Packit Service |
310c69 |
return;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
for (ThreadCount id = 0; id < notifier->threadConfig->baseThreadCount;
|
|
Packit Service |
310c69 |
id++) {
|
|
Packit Service |
310c69 |
ThreadData *threadData = ¬ifier->threadData[id];
|
|
Packit Service |
310c69 |
ReadOnlyListener *listener = threadData->listeners;
|
|
Packit Service |
310c69 |
while (listener != NULL) {
|
|
Packit Service |
310c69 |
ReadOnlyListener *toFree = listener;
|
|
Packit Service |
310c69 |
listener = listener->next;
|
|
Packit Service |
310c69 |
FREE(toFree);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
destroyEnqueueable(¬ifier->completion);
|
|
Packit Service |
310c69 |
FREE(notifier);
|
|
Packit Service |
310c69 |
*notifierPtr = NULL;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Check that a function was called on the admin thread.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @param notifier The notifier
|
|
Packit Service |
310c69 |
* @param caller The name of the function (for logging)
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static void assertOnAdminThread(ReadOnlyNotifier *notifier, const char *caller)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
ThreadID threadID = getCallbackThreadID();
|
|
Packit Service |
310c69 |
ASSERT_LOG_ONLY((getAdminThread(notifier->threadConfig) == threadID),
|
|
Packit Service |
310c69 |
"%s called on admin thread", caller);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
void waitUntilNotEnteringReadOnlyMode(ReadOnlyNotifier *notifier,
|
|
Packit Service |
310c69 |
VDOCompletion *parent)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
if (notifier == NULL) {
|
|
Packit Service |
310c69 |
finishCompletion(parent, VDO_SUCCESS);
|
|
Packit Service |
310c69 |
return;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
assertOnAdminThread(notifier, __func__);
|
|
Packit Service |
310c69 |
if (notifier->waiter != NULL) {
|
|
Packit Service |
310c69 |
finishCompletion(parent, VDO_COMPONENT_BUSY);
|
|
Packit Service |
310c69 |
return;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
uint32_t state = atomicLoad32(¬ifier->state);
|
|
Packit Service |
310c69 |
if ((state == MAY_NOT_NOTIFY) || (state == NOTIFIED)) {
|
|
Packit Service |
310c69 |
// Notifications are already done or disallowed.
|
|
Packit Service |
310c69 |
completeCompletion(parent);
|
|
Packit Service |
310c69 |
return;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
if (compareAndSwap32(¬ifier->state, MAY_NOTIFY, MAY_NOT_NOTIFY)) {
|
|
Packit Service |
310c69 |
// A notification was not in progress, and now they are disallowed.
|
|
Packit Service |
310c69 |
completeCompletion(parent);
|
|
Packit Service |
310c69 |
return;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/*
|
|
Packit Service |
310c69 |
* A notification is in progress, so wait for it to finish. There is no race
|
|
Packit Service |
310c69 |
* here since the notification can't finish while the admin thread is in this
|
|
Packit Service |
310c69 |
* method.
|
|
Packit Service |
310c69 |
*/
|
|
Packit Service |
310c69 |
notifier->waiter = parent;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Complete the process of entering read only mode.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @param completion The read-only mode completion
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static void finishEnteringReadOnlyMode(VDOCompletion *completion)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
ReadOnlyNotifier *notifier = asNotifier(completion);
|
|
Packit Service |
310c69 |
assertOnAdminThread(notifier, __func__);
|
|
Packit Service |
310c69 |
atomicStore32(¬ifier->state, NOTIFIED);
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
VDOCompletion *waiter = notifier->waiter;
|
|
Packit Service |
310c69 |
if (waiter != NULL) {
|
|
Packit Service |
310c69 |
notifier->waiter = NULL;
|
|
Packit Service |
310c69 |
finishCompletion(waiter, completion->result);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Inform each thread that the VDO is in read-only mode.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @param completion The read-only mode completion
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static void makeThreadReadOnly(VDOCompletion *completion)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
ThreadID threadID = completion->callbackThreadID;
|
|
Packit Service |
310c69 |
ReadOnlyNotifier *notifier = asNotifier(completion);
|
|
Packit Service |
310c69 |
ReadOnlyListener *listener = completion->parent;
|
|
Packit Service |
310c69 |
if (listener == NULL) {
|
|
Packit Service |
310c69 |
// This is the first call on this thread
|
|
Packit Service |
310c69 |
ThreadData *threadData = ¬ifier->threadData[threadID];
|
|
Packit Service |
310c69 |
threadData->isReadOnly = true;
|
|
Packit Service |
310c69 |
listener = threadData->listeners;
|
|
Packit Service |
310c69 |
if (threadID == 0) {
|
|
Packit Service |
310c69 |
// Note: This message must be recognizable by Permabit::UserMachine.
|
|
Packit Service |
310c69 |
logErrorWithStringError((int) atomicLoad32(¬ifier->readOnlyError),
|
|
Packit Service |
310c69 |
"Unrecoverable error, entering read-only mode");
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
} else {
|
|
Packit Service |
310c69 |
// We've just finished notifying a listener
|
|
Packit Service |
310c69 |
listener = listener->next;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
if (listener != NULL) {
|
|
Packit Service |
310c69 |
// We have a listener to notify
|
|
Packit Service |
310c69 |
prepareCompletion(completion, makeThreadReadOnly, makeThreadReadOnly,
|
|
Packit Service |
310c69 |
threadID, listener);
|
|
Packit Service |
310c69 |
listener->notify(listener->listener, completion);
|
|
Packit Service |
310c69 |
return;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
// We're done with this thread
|
|
Packit Service |
310c69 |
if (++threadID >= notifier->threadConfig->baseThreadCount) {
|
|
Packit Service |
310c69 |
// There are no more threads
|
|
Packit Service |
310c69 |
prepareCompletion(completion, finishEnteringReadOnlyMode,
|
|
Packit Service |
310c69 |
finishEnteringReadOnlyMode,
|
|
Packit Service |
310c69 |
getAdminThread(notifier->threadConfig), NULL);
|
|
Packit Service |
310c69 |
} else {
|
|
Packit Service |
310c69 |
prepareCompletion(completion, makeThreadReadOnly, makeThreadReadOnly,
|
|
Packit Service |
310c69 |
threadID, NULL);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
invokeCallback(completion);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
void allowReadOnlyModeEntry(ReadOnlyNotifier *notifier, VDOCompletion *parent)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
assertOnAdminThread(notifier, __func__);
|
|
Packit Service |
310c69 |
if (notifier->waiter != NULL) {
|
|
Packit Service |
310c69 |
finishCompletion(parent, VDO_COMPONENT_BUSY);
|
|
Packit Service |
310c69 |
return;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
if (!compareAndSwap32(¬ifier->state, MAY_NOT_NOTIFY, MAY_NOTIFY)) {
|
|
Packit Service |
310c69 |
// Notifications were already allowed or complete
|
|
Packit Service |
310c69 |
completeCompletion(parent);
|
|
Packit Service |
310c69 |
return;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
if ((int) atomicLoad32(¬ifier->readOnlyError) == VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
// We're done
|
|
Packit Service |
310c69 |
completeCompletion(parent);
|
|
Packit Service |
310c69 |
return;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
// There may have been a pending notification
|
|
Packit Service |
310c69 |
if (!compareAndSwap32(¬ifier->state, MAY_NOTIFY, NOTIFYING)) {
|
|
Packit Service |
310c69 |
/*
|
|
Packit Service |
310c69 |
* There wasn't, the error check raced with a thread calling
|
|
Packit Service |
310c69 |
* enterReadOnlyMode() after we set the state to MAY_NOTIFY. It has already
|
|
Packit Service |
310c69 |
* started the notification.
|
|
Packit Service |
310c69 |
*/
|
|
Packit Service |
310c69 |
completeCompletion(parent);
|
|
Packit Service |
310c69 |
return;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
// Do the pending notification.
|
|
Packit Service |
310c69 |
notifier->waiter = parent;
|
|
Packit Service |
310c69 |
makeThreadReadOnly(¬ifier->completion);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
void enterReadOnlyMode(ReadOnlyNotifier *notifier, int errorCode)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
ThreadData *threadData = ¬ifier->threadData[getCallbackThreadID()];
|
|
Packit Service |
310c69 |
if (threadData->isReadOnly) {
|
|
Packit Service |
310c69 |
// This thread has already gone read-only.
|
|
Packit Service |
310c69 |
return;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
// Record for this thread that the VDO is read-only.
|
|
Packit Service |
310c69 |
threadData->isReadOnly = true;
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
if (!compareAndSwap32(¬ifier->readOnlyError, (uint32_t) VDO_SUCCESS,
|
|
Packit Service |
310c69 |
(uint32_t) errorCode)) {
|
|
Packit Service |
310c69 |
// The notifier is already aware of a read-only error
|
|
Packit Service |
310c69 |
return;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
if (compareAndSwap32(¬ifier->state, MAY_NOTIFY, NOTIFYING)) {
|
|
Packit Service |
310c69 |
// Initiate a notification starting on the lowest numbered thread.
|
|
Packit Service |
310c69 |
launchCallback(¬ifier->completion, makeThreadReadOnly, 0);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
bool isReadOnly(ReadOnlyNotifier *notifier)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return notifier->threadData[getCallbackThreadID()].isReadOnly;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
bool isOrWillBeReadOnly(ReadOnlyNotifier *notifier)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return (((int) relaxedLoad32(¬ifier->readOnlyError)) != VDO_SUCCESS);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**********************************************************************/
|
|
Packit Service |
310c69 |
int registerReadOnlyListener(ReadOnlyNotifier *notifier,
|
|
Packit Service |
310c69 |
void *listener,
|
|
Packit Service |
310c69 |
ReadOnlyNotification *notification,
|
|
Packit Service |
310c69 |
ThreadID threadID)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
ReadOnlyListener *readOnlyListener;
|
|
Packit Service |
310c69 |
int result = ALLOCATE(1, ReadOnlyListener, __func__, &readOnlyListener);
|
|
Packit Service |
310c69 |
if (result != VDO_SUCCESS) {
|
|
Packit Service |
310c69 |
return result;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
ThreadData *threadData = ¬ifier->threadData[threadID];
|
|
Packit Service |
310c69 |
*readOnlyListener = (ReadOnlyListener) {
|
|
Packit Service |
310c69 |
.listener = listener,
|
|
Packit Service |
310c69 |
.notify = notification,
|
|
Packit Service |
310c69 |
.next = threadData->listeners,
|
|
Packit Service |
310c69 |
};
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
threadData->listeners = readOnlyListener;
|
|
Packit Service |
310c69 |
return VDO_SUCCESS;
|
|
Packit Service |
310c69 |
}
|