Files
openthread/examples/drivers/windows/include/rtlrefcount.h
T
Nick Banks f600840499 Merge Windows Driver Code (#817)
This is the first of the Windows implementation code that will be merged. This is only the driver code.

Also note the updates to the appveyor configuration. It now builds, installs and queries the status of driver directly on the build machine. Then it builds an 'artifact' which is essentially the binaries packaged up.
2016-10-25 13:38:29 -07:00

442 lines
9.9 KiB
C

/*
* Copyright (c) 2016, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* @brief
* This module contains routines and type definitions for managing reference
* counts.
*
* N.B. The functions defined here use the minimum fencing required for correct
* management of the reference count contract. No additional memory
* ordering should be assumed.
*/
#pragma once
//
// Architecture support macros.
// (Undefined at the bottom to avoid global namespace pollution)
//
#if defined(_WIN64)
#define RtlIncrementLongPtrNoFence InterlockedIncrementNoFence64
#define RtlDecrementLongPtrRelease InterlockedDecrementRelease64
#define RtlExchangeAddLongPtrNoFence InterlockedExchangeAddNoFence64
#define RtlExchangeAddLongPtrRelease InterlockedExchangeAddRelease64
#define RtlCompareExchangeLongPtrNoFence InterlockedCompareExchangeNoFence64
#define RtlCompareExchangeLongPtrRelease InterlockedCompareExchangeRelease64
#else
#define RtlIncrementLongPtrNoFence InterlockedIncrementNoFence
#define RtlDecrementLongPtrRelease InterlockedDecrementRelease
#define RtlExchangeAddLongPtrNoFence InterlockedExchangeAddNoFence
#define RtlExchangeAddLongPtrRelease InterlockedExchangeAddRelease
#define RtlCompareExchangeLongPtrNoFence InterlockedCompareExchangeNoFence
#define RtlCompareExchangeLongPtrRelease InterlockedCompareExchangeRelease
#endif
#if defined(_X86_) || defined(_AMD64_)
#define RtlBarrierAfterInterlock()
#elif defined(_ARM64_)
#define RtlBarrierAfterInterlock() __dmb(_ARM64_BARRIER_ISH)
#elif defined(_ARM_)
#define RtlBarrierAfterInterlock() __dmb(_ARM_BARRIER_ISH)
#else
#define Unsupported architecture.
#endif
#define RTL_REF_COUNT_INIT 1
FORCEINLINE
VOID
RtlInitializeReferenceCount (
_Out_ PRTL_REFERENCE_COUNT RefCount
)
/*++
Routine Description:
This function initializes a reference count to 1.
Arguments:
RefCount - Supplies a pointer to a reference count to initialize.
Return Value:
None.
--*/
{
*RefCount = RTL_REF_COUNT_INIT;
return;
}
FORCEINLINE
VOID
RtlInitializeReferenceCountEx (
_Out_ PRTL_REFERENCE_COUNT RefCount,
_In_ ULONG Bias
)
/*++
Routine Description:
This function initializes a reference count to a positive value.
Arguments:
RefCount - Supplies a pointer to a reference count to initialize.
Bias - Supplies an initial reference count (must be positive).
Return Value:
None.
--*/
{
*RefCount = Bias;
return;
}
FORCEINLINE
VOID
RtlIncrementReferenceCount (
_Inout_ PRTL_REFERENCE_COUNT RefCount
)
/*++
Routine Description:
This function increments the specified reference count, preventing object
deletion.
Arguments:
RefCount - Supplies a pointer to a reference count.
Return Value:
None.
--*/
{
if (RtlIncrementLongPtrNoFence(RefCount) > 1) {
return;
}
__fastfail(FAST_FAIL_INVALID_REFERENCE_COUNT);
}
FORCEINLINE
VOID
RtlIncrementReferenceCountEx (
_Inout_ PRTL_REFERENCE_COUNT RefCount,
_In_ ULONG Bias
)
/*++
Routine Description:
This function increases the specified reference count by the specified bias,
preventing object deletion.
Arguments:
RefCount - Supplies a pointer to a reference count.
Bias - Supplies a reference bias amount.
Return Value:
None.
--*/
{
if (RtlExchangeAddLongPtrNoFence(RefCount, Bias) > 0) {
return;
}
__fastfail(FAST_FAIL_INVALID_REFERENCE_COUNT);
}
FORCEINLINE
BOOLEAN
RtlIncrementReferenceCountNonZero (
_Inout_ volatile RTL_REFERENCE_COUNT *RefCount,
_In_ ULONG Bias
)
/*++
Routine Description:
This function increases the specified reference count by the specified bias,
unless the reference count was previously zero.
Arguments:
RefCount - Supplies a pointer to a reference count.
Bias - Supplies a reference bias amount.
Return Value:
TRUE if the reference count was incremented, FALSE otherwise.
--*/
{
RTL_REFERENCE_COUNT NewValue;
RTL_REFERENCE_COUNT OldValue;
PrefetchForWrite(RefCount);
OldValue = ReadLongPtrNoFence(RefCount);
for (;;) {
NewValue = OldValue + Bias;
if ((ULONG_PTR)NewValue > Bias) {
NewValue = RtlCompareExchangeLongPtrNoFence(RefCount,
NewValue,
OldValue);
if (NewValue == OldValue) {
return TRUE;
}
OldValue = NewValue;
} else if ((ULONG_PTR)NewValue == Bias) {
return FALSE;
} else {
__fastfail(FAST_FAIL_INVALID_REFERENCE_COUNT);
}
}
}
FORCEINLINE
BOOLEAN
RtlDecrementReferenceCount (
_Inout_ PRTL_REFERENCE_COUNT RefCount
)
/*++
Routine Description:
This function reduces the specified reference count, potentially triggering
the destruction of the guarded object.
Arguments:
RefCount - Supplies a pointer to a reference count.
Return Value:
TRUE if the object should be destroyed, FALSE otherwise.
--*/
{
RTL_REFERENCE_COUNT NewValue;
//
// A release fence is required to ensure all guarded memory accesses are
// complete before any thread can begin destroying the object.
//
NewValue = RtlDecrementLongPtrRelease(RefCount);
if (NewValue > 0) {
return FALSE;
} else if (NewValue == 0) {
//
// An acquire fence is required before object destruction to ensure
// that the destructor cannot observe values changing on other threads.
//
RtlBarrierAfterInterlock();
return TRUE;
}
__fastfail(FAST_FAIL_INVALID_REFERENCE_COUNT);
return FALSE;
}
FORCEINLINE
BOOLEAN
RtlDecrementReferenceCountEx (
_Inout_ PRTL_REFERENCE_COUNT RefCount,
_In_ ULONG Bias
)
/*++
Routine Description:
This function reduces the specified reference count by the specified amount,
potentially triggering the destruction of the guarded object.
Arguments:
RefCount - Supplies a pointer to a reference count.
Bias - Supplies a reference bias amount.
Return Value:
TRUE if the object should be destroyed, FALSE otherwise.
--*/
{
RTL_REFERENCE_COUNT NewValue;
//
// A release fence is required to ensure all guarded memory accesses are
// complete before any thread can begin destroying the object.
//
NewValue = RtlExchangeAddLongPtrRelease(RefCount, -(LONG)Bias) - Bias;
if (NewValue > 0) {
return FALSE;
} else if (NewValue == 0) {
//
// An acquire fence is required before object destruction to ensure
// that the destructor cannot observe values changing on other threads.
//
RtlBarrierAfterInterlock();
return TRUE;
}
__fastfail(FAST_FAIL_INVALID_REFERENCE_COUNT);
return FALSE;
}
FORCEINLINE
BOOLEAN
RtlDecrementReferenceCountNonZero (
_Inout_ volatile RTL_REFERENCE_COUNT *RefCount,
_In_ ULONG Bias
)
/*++
Routine Description:
This function reduces the specified reference count by the specified amount,
unless doing so would result in a zero value.
Arguments:
RefCount - Supplies a pointer to a reference count.
Bias - Supplies a reference bias amount.
Return Value:
TRUE if the reference count would be zero, FALSE otherwise.
--*/
{
RTL_REFERENCE_COUNT NewValue;
RTL_REFERENCE_COUNT OldValue;
PrefetchForWrite(RefCount);
OldValue = ReadLongPtrNoFence(RefCount);
for (;;) {
NewValue = OldValue - Bias;
if (NewValue > 0) {
//
// A release fence is required to ensure all guarded memory
// accesses are complete before any thread can begin destroying
// the object.
//
NewValue = RtlCompareExchangeLongPtrRelease(RefCount,
NewValue,
OldValue);
if (NewValue == OldValue) {
return FALSE;
}
OldValue = NewValue;
} else if (NewValue == 0) {
return TRUE;
} else {
__fastfail(FAST_FAIL_INVALID_REFERENCE_COUNT);
}
}
}
#undef RtlIncrementLongPtrNoFence
#undef RtlDecrementLongPtrRelease
#undef RtlExchangeAddLongPtrNoFence
#undef RtlExchangeAddLongPtrRelease
#undef RtlCompareExchangeLongPtrNoFence
#undef RtlCompareExchangeLongPtrRelease
#undef RtlBarrierAfterInterlock