/*
* 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/lockCounter.h#2 $
*/
#ifndef LOCK_COUNTER_H
#define LOCK_COUNTER_H
#include "completion.h"
#include "types.h"
/**
* LockCounter provides a set of shared reference count locks which is safe
* across multiple zones with a minimum of cross-thread synchronization
* operations. For each lock in the set, it maintains a set of per-zone lock
* counts, and a single, atomic count of the number of zones holding locks.
* Whenever a zone's individual counter for a lock goes from 0 to 1, the
* zone count for that lock is incremented. Whenever a zone's individual
* counter for a lock goes from 1 to 0, the zone count for that lock is
* decremented. If the zone count goes to 0, and the lock counter's
* completion is not in use, the completion is launched to inform the counter's
* owner that some lock has been released. It is the owner's responsibility to
* check for which locks have been released, and to inform the lock counter
* that it has received the notification by calling acknowledgeUnlock().
**/
/**
* Create a lock counter.
*
* @param [in] layer The physical layer of the VDO
* @param [in] parent The parent to notify when the lock count goes
* to zero
* @param [in] callback The function to call when the lock count goes
* to zero
* @param [in] threadID The id of thread on which to run the callback
* @param [in] logicalZones The total number of logical zones
* @param [in] physicalZones The total number of physical zones
* @param [in] locks The number of locks
* @param [out] lockCounterPtr A pointer to hold the new counter
*
* @return VDO_SUCCESS or an error
**/
int makeLockCounter(PhysicalLayer *layer,
void *parent,
VDOAction callback,
ThreadID threadID,
ZoneCount logicalZones,
ZoneCount physicalZones,
BlockCount locks,
LockCounter **lockCounterPtr)
__attribute__((warn_unused_result));
/**
* Destroy a lock counter and NULL out the reference to it.
*
* @param lockCounterPtr A pointer to the lock counter reference to free
**/
void freeLockCounter(LockCounter **lockCounterPtr);
/**
* Check whether a lock is locked for a zone type. If the recovery journal has
* a lock on the lock number, both logical and physical zones are considered
* locked.
*
* @param lockCounter The set of locks to check
* @param lockNumber The lock to check
* @param zoneType The type of the zone
*
* @return true
if the specified lock has references (is locked)
**/
bool isLocked(LockCounter *lockCounter,
BlockCount lockNumber,
ZoneType zoneType)
__attribute__((warn_unused_result));
/**
* Initialize the value of the journal zone's counter for a given lock. This
* must be called from the journal zone.
*
* @param counter The counter to initialize
* @param lockNumber Which lock to initialize
* @param value The value to set
**/
void initializeLockCount(LockCounter *counter,
BlockCount lockNumber,
uint16_t value);
/**
* Acquire a reference to a given lock in the specified zone. This method must
* not be used from the journal zone.
*
* @param counter The LockCounter
* @param lockNumber Which lock to increment
* @param zoneType The type of the zone acquiring the reference
* @param zoneID The ID of the zone acquiring the reference
**/
void acquireLockCountReference(LockCounter *counter,
BlockCount lockNumber,
ZoneType zoneType,
ZoneCount zoneID);
/**
* Release a reference to a given lock in the specified zone. This method
* must not be used from the journal zone.
*
* @param counter The LockCounter
* @param lockNumber Which lock to increment
* @param zoneType The type of the zone releasing the reference
* @param zoneID The ID of the zone releasing the reference
**/
void releaseLockCountReference(LockCounter *counter,
BlockCount lockNumber,
ZoneType zoneType,
ZoneCount zoneID);
/**
* Release a single journal zone reference from the journal zone. This method
* must be called from the journal zone.
*
* @param counter The counter from which to release a reference
* @param lockNumber The lock from which to release a reference
**/
void releaseJournalZoneReference(LockCounter *counter, BlockCount lockNumber);
/**
* Release a single journal zone reference from any zone. This method shouldn't
* be called from the journal zone as it would be inefficient; use
* releaseJournalZoneReference() instead.
*
* @param counter The counter from which to release a reference
* @param lockNumber The lock from which to release a reference
**/
void releaseJournalZoneReferenceFromOtherZone(LockCounter *counter,
BlockCount lockNumber);
/**
* Inform a lock counter that an unlock notification was received by the
* caller.
*
* @param counter The counter to inform
**/
void acknowledgeUnlock(LockCounter *counter);
/**
* Prevent the lock counter from issuing notifications.
*
* @param counter The counter
*
* @return true
if the lock counter was not notifying and hence
* the suspend was efficacious
**/
bool suspendLockCounter(LockCounter *counter)
__attribute__((warn_unused_result));
/**
* Re-allow notifications from a suspended lock counter.
*
* @param counter The counter
*
* @return true
if the lock counter was suspended
**/
bool resumeLockCounter(LockCounter *counter)
__attribute__((warn_unused_result));
#endif // LOCK_COUNTER_H