Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

127 lines
4.0 KiB

//** REFPTR.H - referenced pointer definitons.
//
// This file contains the definitions for the referenced-pointer package used
// by the TCP/UDP/IP code.
//
//* Definition of a referenced pointer instance.
//
// The rp_valid field indicates whether the pointer is valid.
// SetRefPtr(..., <value>) is used to install <value> as the pointer.
// ClearRefPtr(...) clears the installed pointer value.
//
// N.B. The pointer value may only be set when invalid. All attempts to set
// the pointer will fail until the installed value is cleared.
//
// If valid, a reference may be taken and the installed pointer captured
// using AcquireRefPtr. The reference taken should then be released
// using ReleaseRefPtr.
//
// N.B. Clearing a pointer may require a wait for all outstanding references
// to be released, so ClearRefPtr(...) releases the object's lock and assumes
// that the resulting IRQL is below DISPATCH_LEVEL.
//
struct RefPtr {
void* rp_ptr;
void* rp_dummy;
CTELock* rp_lock;
BOOLEAN rp_valid;
uint rp_refcnt;
CTEBlockStruc rp_block;
};
typedef struct RefPtr RefPtr;
__inline void
InitRefPtr(RefPtr* RP, CTELock* Lock, void* Dummy)
{
RP->rp_ptr = NULL;
RP->rp_lock = Lock;
RP->rp_valid = FALSE;
RP->rp_refcnt = 0;
RP->rp_dummy = Dummy;
CTEInitBlockStruc(&RP->rp_block);
}
__inline BOOLEAN
RefPtrValid(RefPtr* RP)
{
return RP->rp_valid;
}
__inline void*
AcquireRefPtr(RefPtr* RP)
{
CTEInterlockedIncrementLong(&RP->rp_refcnt);
return RP->rp_ptr;
}
__inline void
ReleaseRefPtr(RefPtr* RP)
{
if (CTEInterlockedDecrementLong(&RP->rp_refcnt) == 0) {
CTESignal(&RP->rp_block, IP_SUCCESS);
}
}
__inline IP_STATUS
SetRefPtr(RefPtr* RP, void* Ptr)
{
ASSERT(Ptr != NULL);
// We must synchronize the pointer-installation with the execution
// of all threads holding references. Again, a sequence of operations
// is required, in the given order:
// - make an initial reference for the pointer to be installed;
// if there were any existing references then someone beat us
// into the registration and we must fail this request.
// - install the new pointer; this is done before setting the flag
// to ensure that the pointer is available before any thread
// attempts to refer to it.
// - set the flag indicating the pointer has been enabled.
if (CTEInterlockedIncrementLong(&RP->rp_refcnt) != 1) {
ReleaseRefPtr(RP);
return IP_GENERAL_FAILURE;
}
InterlockedExchangePointer((PVOID*)&RP->rp_ptr, Ptr);
RP->rp_valid = TRUE;
return IP_SUCCESS;
}
__inline IP_STATUS
ClearRefPtr(RefPtr* RP, CTELockHandle* LockHandle)
{
if (!RP->rp_valid) {
return IP_GENERAL_FAILURE;
}
// We must now synchronize the clearing of the pointer with
// the execution of all threads holding references to it. This involves
// the following operations, *in the given order*:
// - clear the 'enabled' flag and install the dummy pointer value;
// this ensures that no additional references will be made to the
// pointer until we return control, and that any references begun
// after we set the flag will hold the dummy rather than the
// actual pointer.
// - clear the event in case we need to wait for outstanding references
// to be released; the event might still be signalled from a
// superfluous dereference during a previous clearing.
// - drop the initial reference made to the pointer, and wait for all
// outstanding references (if any) to be released.
RP->rp_valid = FALSE;
InterlockedExchangePointer(&RP->rp_ptr, RP->rp_dummy);
CTEClearSignal(&RP->rp_block);
if (CTEInterlockedDecrementLong(&RP->rp_refcnt) != 0) {
CTEFreeLock(RP->rp_lock, *LockHandle);
CTEBlock(&RP->rp_block);
CTEGetLock(RP->rp_lock, LockHandle);
}
return IP_SUCCESS;
}