mirror of https://github.com/lianthony/NT4.0
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.
359 lines
7.2 KiB
359 lines
7.2 KiB
/*++
|
|
|
|
Copyright (c) 1991 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
blkcomm.c
|
|
|
|
Abstract:
|
|
|
|
This module implements routines for managing comm device blocks.
|
|
|
|
Author:
|
|
|
|
David Treadwell (davidtr) 19-Dec-1991
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
#if SRV_COMM_DEVICES
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text( PAGE, SrvAllocateCommDevice )
|
|
#pragma alloc_text( PAGE, SrvCheckAndReferenceCommDevice )
|
|
#pragma alloc_text( PAGE, SrvDereferenceCommDevice )
|
|
#pragma alloc_text( PAGE, SrvFreeCommDevice )
|
|
#pragma alloc_text( PAGE, SrvReferenceCommDevice )
|
|
#endif
|
|
|
|
|
|
VOID
|
|
SrvAllocateCommDevice (
|
|
OUT PCOMM_DEVICE *CommDevice,
|
|
IN PUNICODE_STRING NtPathName,
|
|
IN PUNICODE_STRING DosPathName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function allocates a comm device Block from the FSP heap.
|
|
|
|
Arguments:
|
|
|
|
CommDevice - Returns a pointer to the comm device block, or NULL if
|
|
no heap space was available.
|
|
|
|
NtPathName - The NT path of the corresponding device.
|
|
|
|
DosPathName - The DOS path of the corresponding device.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG blockLength;
|
|
PCOMM_DEVICE commDevice;
|
|
|
|
PAGED_CODE( );
|
|
|
|
//
|
|
// Attempt to allocate from the heap.
|
|
//
|
|
|
|
blockLength = sizeof(COMM_DEVICE) +
|
|
NtPathName->Length + sizeof(*NtPathName->Buffer) +
|
|
DosPathName->Length + sizeof(*DosPathName->Buffer);
|
|
|
|
commDevice = ALLOCATE_HEAP( blockLength, BlockTypeCommDevice );
|
|
*CommDevice = commDevice;
|
|
|
|
if ( commDevice == NULL ) {
|
|
INTERNAL_ERROR(
|
|
ERROR_LEVEL_EXPECTED,
|
|
"SrvAllocateCommDevice: Unable to allocate %d bytes from heap",
|
|
blockLength,
|
|
NULL
|
|
);
|
|
|
|
// An error is logged by the caller.
|
|
|
|
return;
|
|
}
|
|
|
|
IF_DEBUG(HEAP) {
|
|
SrvPrint1( "SrvAllocateCommDevice: Allocated comm device at %lx\n",
|
|
commDevice );
|
|
}
|
|
|
|
RtlZeroMemory( commDevice, blockLength );
|
|
|
|
SET_BLOCK_TYPE_STATE_SIZE( commDevice, BlockTypeCommDevice, BlockStateActive, blockLength );
|
|
|
|
//
|
|
// Set the reference count to 1 to account for the caller's pointer.
|
|
// Comm devices are "temporary" objects, which means that as soon
|
|
// as the last pointer to one goes away, so does the comm device.
|
|
//
|
|
|
|
commDevice->BlockHeader.ReferenceCount = 1;
|
|
|
|
//
|
|
// Initialize the NT and DOS path names.
|
|
//
|
|
|
|
commDevice->NtPathName.Length = NtPathName->Length;
|
|
commDevice->NtPathName.MaximumLength =
|
|
(USHORT)(NtPathName->Length + sizeof(*NtPathName->Buffer));
|
|
commDevice->NtPathName.Buffer = (PWCH)(commDevice + 1);
|
|
|
|
RtlCopyUnicodeString( &commDevice->NtPathName, NtPathName );
|
|
|
|
commDevice->DosPathName.Length = DosPathName->Length;
|
|
commDevice->DosPathName.MaximumLength =
|
|
(USHORT)(DosPathName->Length + sizeof(*DosPathName->Buffer));
|
|
commDevice->DosPathName.Buffer =
|
|
(PWCH)( (PCHAR)commDevice->NtPathName.Buffer + NtPathName->Length +
|
|
sizeof(WCHAR) );
|
|
|
|
RtlCopyUnicodeString( &commDevice->DosPathName, DosPathName );
|
|
|
|
INITIALIZE_REFERENCE_HISTORY( commDevice );
|
|
|
|
return;
|
|
|
|
} // SrvAllocateCommDevice
|
|
|
|
|
|
BOOLEAN SRVFASTCALL
|
|
SrvCheckAndReferenceCommDevice (
|
|
PCOMM_DEVICE CommDevice
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function atomically verifies that a comm device is active and
|
|
increments the reference count on the comm device if it is.
|
|
|
|
Arguments:
|
|
|
|
CommDevice - Address of comm device
|
|
|
|
Return Value:
|
|
|
|
BOOLEAN - Returns TRUE if the comm device is active, FALSE otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
PAGED_CODE( );
|
|
|
|
//
|
|
// Acquire the lock that guards the comm device's state field.
|
|
//
|
|
|
|
ACQUIRE_LOCK( &SrvShareLock );
|
|
|
|
//
|
|
// If the comm device is active, reference it and return TRUE.
|
|
//
|
|
|
|
if ( GET_BLOCK_STATE(CommDevice) == BlockStateActive ) {
|
|
|
|
SrvReferenceCommDevice( CommDevice );
|
|
|
|
RELEASE_LOCK( &SrvShareLock );
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
//
|
|
// The comm device isn't active. Return FALSE.
|
|
//
|
|
|
|
RELEASE_LOCK( &SrvShareLock );
|
|
|
|
return FALSE;
|
|
|
|
} // SrvCheckAndReferenceCommDevice
|
|
|
|
|
|
VOID SRVFASTCALL
|
|
SrvDereferenceCommDevice (
|
|
IN PCOMM_DEVICE CommDevice
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function decrements the reference count on a comm device. If the
|
|
reference count goes to zero, the comm device block is deleted.
|
|
|
|
Arguments:
|
|
|
|
CommDevice - Address of comm device
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PAGED_CODE( );
|
|
|
|
//
|
|
// Enter a critical section and decrement the reference count on the
|
|
// block.
|
|
//
|
|
|
|
ACQUIRE_LOCK( &SrvShareLock );
|
|
|
|
IF_DEBUG(REFCNT) {
|
|
SrvPrint2( "Dereferencing comm device %lx; old refcnt %lx\n",
|
|
CommDevice, CommDevice->BlockHeader.ReferenceCount );
|
|
}
|
|
|
|
ASSERT( GET_BLOCK_TYPE( CommDevice ) == BlockTypeCommDevice );
|
|
ASSERT( (LONG)CommDevice->BlockHeader.ReferenceCount > 0 );
|
|
UPDATE_REFERENCE_HISTORY( CommDevice, TRUE );
|
|
|
|
if ( --CommDevice->BlockHeader.ReferenceCount == 0 ) {
|
|
|
|
//
|
|
// The new reference count is 0, meaning that it's time to
|
|
// delete this block.
|
|
//
|
|
|
|
RELEASE_LOCK( &SrvShareLock );
|
|
|
|
ASSERT( !CommDevice->InUse );
|
|
|
|
//
|
|
// Remove the comm device from the global list of comm devices.
|
|
//
|
|
|
|
SrvRemoveEntryOrderedList( &SrvCommDeviceList, CommDevice );
|
|
|
|
//
|
|
// Free the comm device block.
|
|
//
|
|
|
|
SrvFreeCommDevice( CommDevice );
|
|
|
|
} else {
|
|
|
|
RELEASE_LOCK( &SrvShareLock );
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
} // SrvDereferenceCommDevice
|
|
|
|
|
|
VOID
|
|
SrvFreeCommDevice (
|
|
IN PCOMM_DEVICE CommDevice
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function returns a comm device block to system pool.
|
|
|
|
Arguments:
|
|
|
|
CommDevice - Address of comm device
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PAGED_CODE( );
|
|
|
|
DEBUG SET_BLOCK_TYPE_STATE_SIZE( CommDevice, BlockTypeGarbage, BlockStateDead, -1 );
|
|
DEBUG CommDevice->BlockHeader.ReferenceCount = (ULONG)-1;
|
|
TERMINATE_REFERENCE_HISTORY( CommDevice );
|
|
|
|
//
|
|
// Deallocate the comm device's memory.
|
|
//
|
|
|
|
FREE_HEAP( CommDevice );
|
|
IF_DEBUG(HEAP) {
|
|
SrvPrint1( "SrvFreeCommDevice: Freed comm device block at %lx\n",
|
|
CommDevice );
|
|
}
|
|
|
|
return;
|
|
|
|
} // SrvFreeCommDevice
|
|
|
|
|
|
VOID
|
|
SrvReferenceCommDevice (
|
|
PCOMM_DEVICE CommDevice
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function increments the reference count on a comm device block.
|
|
|
|
Arguments:
|
|
|
|
CommDevice - Address of comm device block
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PAGED_CODE( );
|
|
|
|
//
|
|
// Enter a critical section and increment the reference count on the
|
|
// comm device.
|
|
//
|
|
|
|
ACQUIRE_LOCK( &SrvShareLock );
|
|
|
|
ASSERT( (LONG)CommDevice->BlockHeader.ReferenceCount > 0 );
|
|
ASSERT( GET_BLOCK_TYPE(CommDevice) == BlockTypeCommDevice );
|
|
// ASSERT( GET_BLOCK_STATE(CommDevice) == BlockStateActive );
|
|
UPDATE_REFERENCE_HISTORY( CommDevice, FALSE );
|
|
|
|
CommDevice->BlockHeader.ReferenceCount++;
|
|
|
|
IF_DEBUG(REFCNT) {
|
|
SrvPrint2( "Referencing comm device %lx; new refcnt %lx\n",
|
|
CommDevice, CommDevice->BlockHeader.ReferenceCount );
|
|
}
|
|
|
|
RELEASE_LOCK( &SrvShareLock );
|
|
|
|
return;
|
|
|
|
} // SrvReferenceCommDevice
|
|
#endif // SRV_COMM_DEVICES
|