windows-nt/Source/XPSP1/NT/net/sockets/winsock2/wsp/afdsys/group.c
2020-09-26 16:20:57 +08:00

554 lines
11 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
group.c
Abstract:
This module contains Group ID managment routines.
Group IDs identify an AFD_GROUP_ENTRY structure in a lookup table.
Each AFD_GROUP_ENTRY contains a reference count and a type (either
GroupTypeConstrained or GroupTypeUnconstrained). Free group IDs are
linked together in a doubly-linked list. As group IDs are allocated,
they are removed from this list. Once the free list becomes empty,
the lookup table is grown appropriately.
Author:
Keith Moore (keithmo) 06-Jun-1996
Revision History:
--*/
#include "afdp.h"
//
// Private constants.
//
#define AFD_GROUP_TABLE_GROWTH 32 // entries
//
// Private types.
//
typedef struct _AFD_GROUP_ENTRY {
union {
LIST_ENTRY ListEntry;
struct {
AFD_GROUP_TYPE GroupType;
LONG ReferenceCount;
};
};
} AFD_GROUP_ENTRY, *PAFD_GROUP_ENTRY;
//
// Private globals.
//
PERESOURCE AfdGroupTableResource;
PAFD_GROUP_ENTRY AfdGroupTable;
LIST_ENTRY AfdFreeGroupList;
LONG AfdGroupTableSize;
//
// Private functions.
//
PAFD_GROUP_ENTRY
AfdMapGroupToEntry(
IN LONG Group
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text( INIT, AfdInitializeGroup )
#pragma alloc_text( PAGE, AfdTerminateGroup )
#pragma alloc_text( PAGE, AfdReferenceGroup )
#pragma alloc_text( PAGE, AfdDereferenceGroup )
#pragma alloc_text( PAGE, AfdGetGroup )
#endif
BOOLEAN
AfdInitializeGroup(
VOID
)
/*++
Routine Description:
Initializes any globals necessary for the group ID package.
Return Value:
BOOLEAN - TRUE if successful, FALSE otherwise.
--*/
{
//
// Initialize the group globals.
//
AfdGroupTableResource = AFD_ALLOCATE_POOL_PRIORITY(
NonPagedPool,
sizeof(*AfdGroupTableResource),
AFD_RESOURCE_POOL_TAG,
HighPoolPriority
);
if( AfdGroupTableResource == NULL ) {
return FALSE;
}
ExInitializeResourceLite( AfdGroupTableResource );
AfdGroupTable = NULL;
InitializeListHead( &AfdFreeGroupList );
AfdGroupTableSize = 0;
return TRUE;
} // AfdInitializeGroup
VOID
AfdTerminateGroup(
VOID
)
/*++
Routine Description:
Destroys any globals created for the group ID package.
--*/
{
if( AfdGroupTableResource != NULL ) {
ExDeleteResourceLite( AfdGroupTableResource );
AFD_FREE_POOL(
AfdGroupTableResource,
AFD_RESOURCE_POOL_TAG
);
AfdGroupTableResource = NULL;
}
if( AfdGroupTable != NULL ) {
AFD_FREE_POOL(
AfdGroupTable,
AFD_GROUP_POOL_TAG
);
AfdGroupTable = NULL;
}
InitializeListHead( &AfdFreeGroupList );
AfdGroupTableSize = 0;
} // AfdTerminateGroup
BOOLEAN
AfdReferenceGroup(
IN LONG Group,
OUT PAFD_GROUP_TYPE GroupType
)
/*++
Routine Description:
Bumps the reference count associated with the given group ID.
Arguments:
Group - The group ID to reference.
GroupType - Returns the type of the group.
Returns:
BOOLEAN - TRUE if the group ID was valid, FALSE otherwise.
--*/
{
PAFD_GROUP_ENTRY groupEntry;
AFD_GROUP_TYPE groupType;
groupEntry = AfdMapGroupToEntry( Group );
if( groupEntry != NULL ) {
groupType = groupEntry->GroupType;
if( groupType == GroupTypeConstrained ||
groupType == GroupTypeUnconstrained ) {
groupEntry->ReferenceCount++;
*GroupType = groupType;
} else {
groupEntry = NULL;
}
ExReleaseResourceLite( AfdGroupTableResource );
KeLeaveCriticalRegion ();
}
return (BOOLEAN)( groupEntry != NULL );
} // AfdReferenceGroup
BOOLEAN
AfdDereferenceGroup(
IN LONG Group
)
/*++
Routine Description:
Decrements the reference count associated with the given group ID.
If the ref count drops to zero, the group ID is freed.
Arguments:
Group - The group ID to dereference.
Returns:
BOOLEAN - TRUE if the group ID was valid, FALSE otherwise.
--*/
{
PAFD_GROUP_ENTRY groupEntry;
AFD_GROUP_TYPE groupType;
groupEntry = AfdMapGroupToEntry( Group );
if( groupEntry != NULL ) {
groupType = groupEntry->GroupType;
if( groupType == GroupTypeConstrained ||
groupType == GroupTypeUnconstrained ) {
ASSERT( groupEntry->ReferenceCount > 0 );
groupEntry->ReferenceCount--;
if( groupEntry->ReferenceCount == 0 ) {
InsertTailList(
&AfdFreeGroupList,
&groupEntry->ListEntry
);
}
} else {
groupEntry = NULL;
}
ExReleaseResourceLite( AfdGroupTableResource );
KeLeaveCriticalRegion ();
}
return (BOOLEAN)( groupEntry != NULL );
} // AfdDereferenceGroup
BOOLEAN
AfdGetGroup(
IN OUT PLONG Group,
OUT PAFD_GROUP_TYPE GroupType
)
/*++
Routine Description:
Examines the incoming group. If is zero, then nothing is done. If it
is SG_CONSTRAINED_GROUP, then a new constrained group ID is created.
If it is SG_UNCONSTRAINED_GROUP, then a new unconstrained group ID is
created. Otherwise, it must identify an existing group, so that group
is referenced.
Arguments:
Group - Points to the group ID to examine/modify.
GroupType - Returns the type of the group.
Return Value:
BOOLEAN - TRUE if successful, FALSE otherwise.
--*/
{
LONG groupValue;
PAFD_GROUP_ENTRY groupEntry;
PAFD_GROUP_ENTRY newGroupTable;
LONG newGroupTableSize;
LONG i;
PLIST_ENTRY listEntry;
groupValue = *Group;
//
// Zero means "no group", so just ignore it.
//
if( groupValue == 0 ) {
*GroupType = GroupTypeNeither;
return TRUE;
}
//
// If we're being asked to create a new group, do it.
//
if( groupValue == SG_CONSTRAINED_GROUP ||
groupValue == SG_UNCONSTRAINED_GROUP ) {
//
// Lock the table.
//
//
// Make sure the thread in which we execute cannot get
// suspeneded in APC while we own the global resource.
//
KeEnterCriticalRegion ();
ExAcquireResourceExclusiveLite( AfdGroupTableResource, TRUE );
//
// See if there's room at the inn.
//
if( IsListEmpty( &AfdFreeGroupList ) ) {
//
// No room, we'll need to create/expand the table.
//
newGroupTableSize = AfdGroupTableSize + AFD_GROUP_TABLE_GROWTH;
newGroupTable = AFD_ALLOCATE_POOL(
PagedPool,
newGroupTableSize * sizeof(AFD_GROUP_ENTRY),
AFD_GROUP_POOL_TAG
);
if( newGroupTable == NULL ) {
ExReleaseResourceLite( AfdGroupTableResource );
KeLeaveCriticalRegion ();
return FALSE;
}
if( AfdGroupTable == NULL ) {
//
// This is the initial table allocation, so reserve the
// first three entries (0, SG_UNCONSTRAINED_GROUP, and
// SG_CONSTRAINED_GROUP).
//
for( ;
AfdGroupTableSize <= SG_CONSTRAINED_GROUP ||
AfdGroupTableSize <= SG_UNCONSTRAINED_GROUP ;
AfdGroupTableSize++ ) {
newGroupTable[AfdGroupTableSize].ReferenceCount = 0;
newGroupTable[AfdGroupTableSize].GroupType = GroupTypeNeither;
}
} else {
//
// Copy the old table into the new table, then free the
// old table.
//
RtlCopyMemory(
newGroupTable,
AfdGroupTable,
AfdGroupTableSize * sizeof(AFD_GROUP_ENTRY)
);
AFD_FREE_POOL(
AfdGroupTable,
AFD_GROUP_POOL_TAG
);
}
//
// Add the new entries to the free list.
//
for( i = newGroupTableSize - 1 ; i >= AfdGroupTableSize ; i-- ) {
InsertHeadList(
&AfdFreeGroupList,
&newGroupTable[i].ListEntry
);
}
AfdGroupTable = newGroupTable;
AfdGroupTableSize = newGroupTableSize;
}
//
// Pull the next free entry off the list.
//
ASSERT( !IsListEmpty( &AfdFreeGroupList ) );
listEntry = RemoveHeadList( &AfdFreeGroupList );
groupEntry = CONTAINING_RECORD(
listEntry,
AFD_GROUP_ENTRY,
ListEntry
);
groupEntry->ReferenceCount = 1;
groupEntry->GroupType = (AFD_GROUP_TYPE)groupValue;
*Group = (LONG)( groupEntry - AfdGroupTable );
*GroupType = groupEntry->GroupType;
ExReleaseResourceLite( AfdGroupTableResource );
KeLeaveCriticalRegion ();
return TRUE;
}
//
// Otherwise, just reference the group.
//
return AfdReferenceGroup( groupValue, GroupType );
} // AfdGetGroup
PAFD_GROUP_ENTRY
AfdMapGroupToEntry(
IN LONG Group
)
/*++
Routine Description:
Maps the given group ID to the corresponding AFD_GROUP_ENTRY structure.
N.B. This routine returns with AfdGroupTableResource held if successful.
Arguments:
Group - The group ID to map.
Return Value:
PAFD_GROUP_ENTRY - The entry corresponding to the group ID if successful,
NULL otherwise.
--*/
{
PAFD_GROUP_ENTRY groupEntry;
//
// Lock the table.
//
//
// Make sure the thread in which we execute cannot get
// suspeneded in APC while we own the global resource.
//
KeEnterCriticalRegion ();
ExAcquireResourceExclusiveLite( AfdGroupTableResource, TRUE );
//
// Validate the group ID.
//
if( Group > 0 && Group < AfdGroupTableSize ) {
groupEntry = AfdGroupTable + Group;
//
// The group ID is within legal range. Ensure it's in use.
// In the AFD_GROUP_ENTRY structure, the GroupType field is
// overlayed with ListEntry.Flink due to the internal union.
// We can use this knowledge to quickly validate that this
// entry is in use.
//
if( groupEntry->GroupType == GroupTypeConstrained ||
groupEntry->GroupType == GroupTypeUnconstrained ) {
return groupEntry;
}
}
//
// Invalid group ID, fail it.
//
ExReleaseResourceLite( AfdGroupTableResource );
KeLeaveCriticalRegion ();
return NULL;
} // AfdMapGroupToEntry