/*++

Copyright (c) 1997 Microsoft Corporation

Module Name:

    resource.h

Abstract:

    This header holds declarations for a shared-resource synchronization object.

Author:

    Abolade Gbadegesin (t-abolag)   11-July-1997

Revision History:

--*/


#ifndef _NAT_RESOURCE_H_
#define _NAT_RESOURCE_H_


//
// NAT_RESOURCE
//
// This structure contains the fields used for shared-exclusive synchronization.
//

typedef struct _NAT_RESOURCE {

    KSPIN_LOCK  ReaderSpinLock;
    LONG        ReaderCount;
    KSPIN_LOCK  WriterSpinLock;
    KIRQL       WriterIrql;

} NAT_RESOURCE, *PNAT_RESOURCE;


//
// RESOURCE ROUTINES
//


#define USES_NAT_RESOURCE() \
    KIRQL _ReaderIrql; \
    KIRQL _WriterIrql


// 
// VOID
// NatInitializeResource(
//    PNAT_RESOURCE   Resource
//    );
//

#define NatInitializeResource(Resource) { \
    (Resource)->ReaderCount = 0; \
    KeInitializeSpinLock(&(Resource)->ReaderSpinLock); \
    KeInitializeSpinLock(&(Resource)->WriterSpinLock); \
}


//
// VOID
// NatAcquireResourceShared(
//     PNAT_RESOURCE   Resource
//     );
//

#define NatAcquireResourceShared(Resource) { \
    KeAcquireSpinLock(&(Resource)->ReaderSpinLock, &_ReaderIrql); \
    if (InterlockedIncrement(&(Resource)->ReaderCount) == 1) { \
        KeAcquireSpinLockAtDpcLevel(&(Resource)->WriterSpinLock); \
    } \
    KeReleaseSpinLockFromDpcLevel(&(Resource)->ReaderSpinLock); \
}


//
// VOID
// NatReleaseResourceShared(
//    PNAT_RESOURCE   Resource
//    );
//

#define NatReleaseResourceShared(Resource) { \
    if (InterlockedDecrement(&(Resource)->ReaderCount) == 0) { \
        KeReleaseSpinLockFromDpcLevel(&(Resource)->WriterSpinLock); \
    } \
    KeLowerIrql(_ReaderIrql); \
}


//
// VOID
// NatAcquireResourceExclusive(
//     PNAT_RESOURCE   Resource
//    );
//

#define NatAcquireResourceExclusive(Resource) \
    KeAcquireSpinLock(&(Resource)->WriterSpinLock, &(Resource)->WriterIrql)


//
// VOID
// NatReleaseResourceExclusive(
//     PNAT_RESOURCE   Resource
//     );
//

#define NatReleaseResourceExclusive(Resource) \
    KeReleaseSpinLock(&(Resource)->WriterSpinLock, (Resource)->WriterIrql)


//
// VOID
// NatConvertSharedToExclusive(
//      PNAT_RESOURCE   Resource
//      );
//

#define NatConvertSharedToExclusive(Resource) { \
    KeAcquireSpinLockAtDpcLevel(&(Resource)->ReaderSpinLock); \
    if (InterlockedDecrement(&(Resource)->ReaderCount) == 0) { \
        KeReleaseSpinLockFromDpcLevel(&(Resource)->ReaderSpinLock); \
    } \
    else { \
        KeReleaseSpinLockFromDpcLevel(&(Resource)->ReaderSpinLock); \
        KeAcquireSpinLockAtDpcLevel(&(Resource)->WriterSpinLock); \
    } \
}


//
// VOID
// NatConvertedExclusiveToShared(
//      PNAT_RESOURCE   Resource
//      );
//

#define NatConvertedExclusiveToShared(Resource) { \
    KeReleaseSpinLockFromDpcLevel(&(Resource)->WriterSpinLock); \
    KeAcquireSpinLockAtDpcLevel(&(Resource)->ReaderSpinLock); \
    if (InterlockedIncrement(&(Resource)->ReaderCount) == 1) { \
        KeAcquireSpinLockAtDpcLevel(&(Resource)->WriterSpinLock); \
    } \
    KeReleaseSpinLockFromDpcLevel(&(Resource)->ReaderSpinLock); \
}


//
// VOID
// NatReleaseConvertedExclusive(
//      PNAT_RESOURCE   Resource
//      );
//

#define NatReleaseConvertedExclusive(Resource) { \
    KeReleaseSpinLock(&(Resource)->WriterSpinLock, _ReaderIrql); \
}


#endif // _NAT_RESOURCE_H_