|
|
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1997.
//
// File: sht.cxx
//
// Contents: Small Handle table implementation
//
// Classes:
//
// Functions:
//
// History: 2-03-97 RichardW Created
//
//----------------------------------------------------------------------------
#include <lsapch.hxx>
#include "sht.hxx"
#if DBG
#define DBG_SHT 1
#else
#define DBG_SHT 0
#endif
#define SHT_ACTION_ADDREF 0
#define SHT_ACTION_DELREF 1
#define SHT_ACTION_FORCEDEL 2
#define SHT_ACTION_VALIDATE 3
#define SHT_ACTION_ADDHANDLE 4
#define SHT_ACTION_DELHANDLE 5
#define SHT_ACTION_MASK 0x0000FFFF
#define SHT_ACTION_LOCKED 0x00010000
#define SHTP_HANDLE_CHECKED 0x20000000
#define ShtLockTable( t ) \
if ( (((PSMALL_HANDLE_TABLE) t)->Flags & SHT_NO_SERIALIZE ) == 0 ) \ { \ RtlEnterCriticalSection( &((PSMALL_HANDLE_TABLE)t)->Lock ); \ }
#define ShtUnlockTable( t ) \
if ( (((PSMALL_HANDLE_TABLE) t)->Flags & SHT_NO_SERIALIZE ) == 0 ) \ { \ RtlLeaveCriticalSection( &((PSMALL_HANDLE_TABLE)t)->Lock ); \ }
HP_INITIALIZE_FN ShtInitialize ; HP_CREATE_FN ShtCreate ; HP_DELETE_FN ShtDelete ; HP_ADD_HANDLE_FN ShtAddHandle ; HP_DELETE_HANDLE_FN ShtDeleteHandle ; HP_VALIDATE_HANDLE_FN ShtValidateHandle ; HP_REF_HANDLE_FN ShtRefHandle ; HP_DEREF_HANDLE_KEY_FN ShtDerefHandleKey ; HP_GET_HANDLE_CONTEXT_FN ShtGetHandleContext ; HP_RELEASE_CONTEXT_FN ShtReleaseContext ;
HANDLE_PACKAGE SmallHandlePackage = { sizeof( SMALL_HANDLE_TABLE), ShtInitialize, ShtCreate, ShtDelete, ShtAddHandle, ShtDeleteHandle, ShtValidateHandle, ShtRefHandle, ShtDerefHandleKey, ShtGetHandleContext, ShtReleaseContext };
//+---------------------------------------------------------------------------
//
// Function: ShtInitialize
//
// Synopsis: Initialize the small handle table package
//
// Arguments: (none)
//
// History: 3-04-97 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
BOOL ShtInitialize( VOID ) { return TRUE ; }
//+---------------------------------------------------------------------------
//
// Function: ShtCreate
//
// Synopsis: Create a small handle table
//
// Arguments: [Flags] -- Options
// [HandleTable] -- Space to fill
//
// History: 3-04-97 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
PVOID ShtCreate( IN ULONG Flags, IN PVOID HandleTable OPTIONAL, IN PHP_ENUM_CALLBACK_FN Callback OPTIONAL ) { PSMALL_HANDLE_TABLE Table ;
if ( HandleTable ) { Table = (PSMALL_HANDLE_TABLE) HandleTable ; } else { Table = (PSMALL_HANDLE_TABLE) LsapAllocatePrivateHeap( sizeof( SMALL_HANDLE_TABLE ) ); }
if ( Table ) { Table->Tag = SHT_TAG ; Table->Count = 0 ; Table->Flags = 0 ;
InitializeListHead( &Table->List );
//
// Turn on general flags:
//
Table->Flags = (Flags & HANDLE_PACKAGE_GENERAL_FLAGS);
if ( Flags & HANDLE_PACKAGE_NO_SERIALIZE ) { Table->Flags |= SHT_NO_SERIALIZE ; } else { NTSTATUS Status = RtlInitializeCriticalSection( &Table->Lock );
if (!NT_SUCCESS(Status)) { if ( !HandleTable ) { LsapFreePrivateHeap( Table ); }
Table = NULL ; } }
if ( Table ) {
if ( Flags & HANDLE_PACKAGE_CALLBACK_ON_DELETE ) { Table->DeleteCallback = Callback ; }
if ( HandleTable ) { Table->Flags |= SHT_NO_FREE ; } }
}
return Table ; }
//+---------------------------------------------------------------------------
//
// Function: ShtDelete
//
// Synopsis: Deletes a handle table. Callback is called for every handle in
// the table.
//
// Arguments: [HandleTable] --
// [Callback] --
//
// History: 3-04-97 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
BOOL ShtDelete( PVOID HandleTable, PHP_ENUM_CALLBACK_FN Callback ) { PSMALL_HANDLE_TABLE Table ; PSEC_HANDLE_ENTRY Entry ; PLIST_ENTRY Scan ; ULONG RefCount ;
Table = (PSMALL_HANDLE_TABLE) HandleTable ;
ShtLockTable( Table );
Table->Flags |= SHT_DELETE_PENDING ;
while ( !IsListEmpty( &Table->List ) ) { Scan = RemoveHeadList( &Table->List );
Table->Count--;
Entry = (PSEC_HANDLE_ENTRY) Scan ;
Table->PendingHandle = Entry ;
Entry->Flags |= SEC_HANDLE_FLAG_DELETE_PENDING ;
RefCount = Entry->HandleCount ; Entry->HandleCount = 1; Entry->RefCount = 1 ;
if ( ( Callback ) && ( ( Entry->Flags & SEC_HANDLE_FLAG_NO_CALLBACK ) == 0 ) ) { Callback( &Entry->Handle, Entry->Context, RefCount ); }
LsapFreePrivateHeap( Entry );
}
DsysAssert( Table->Count == 0 );
if ( ( Table->Flags & SHT_NO_SERIALIZE ) == 0 ) { RtlDeleteCriticalSection( &Table->Lock ); }
if ( (Table->Flags & SHT_NO_FREE) == 0 ) { LsapFreePrivateHeap( Table ); }
return TRUE ; }
#if DBG_SHT
//+---------------------------------------------------------------------------
//
// Function: ShtpValidateList
//
// Synopsis: Debug only - validates a handle table
//
// Arguments: [Table] --
//
// History: 3-04-97 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
VOID ShtpValidateList( PSMALL_HANDLE_TABLE Table, BOOL Locked ) { PLIST_ENTRY List ; PSEC_HANDLE_ENTRY Entry ; PSEC_HANDLE_ENTRY Back ; ULONG Count ;
if ( !Locked ) { ShtLockTable( Table ); }
List = Table->List.Flink ; Count = 0 ;
while ( List && (List != &Table->List) ) { Entry = (PSEC_HANDLE_ENTRY) List ;
if ( List->Blink != &Table->List ) { Back = (PSEC_HANDLE_ENTRY) List->Blink ;
DsysAssertMsg( Back->Handle.dwUpper <= Entry->Handle.dwUpper, "Handle Table Corrupt (1)" ); }
List = List->Flink ; Count++ ; }
DsysAssertMsg( List, "Handle Table Corrupt (2)" ); DsysAssertMsg( Count == Table->Count, "Handle Table Corrupt (3)" );
if ( !Locked ) { ShtUnlockTable( Table ); } }
#endif
//+---------------------------------------------------------------------------
//
// Function: ShtpFindHandle
//
// Synopsis: General worker function for locating handles in the table
//
// Arguments: [Table] -- Table to search
// [Handle] -- Handle to find
// [Action] -- Action to take
// [Removed] -- Flag if it was removed or just deref'd
//
// History: 3-04-97 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
PSEC_HANDLE_ENTRY ShtpFindHandle( PSMALL_HANDLE_TABLE Table, PSecHandle Handle, ULONG Action, PBOOL Removed OPTIONAL ) { PLIST_ENTRY Scan ; PSEC_HANDLE_ENTRY Entry ; BOOL Delete = FALSE ; Entry = NULL ; BOOL Locked ; BOOL Checked ;
Locked = (Action & SHT_ACTION_LOCKED) == SHT_ACTION_LOCKED ; Checked = (Action & SHTP_HANDLE_CHECKED) == SHTP_HANDLE_CHECKED ; Action = Action & SHT_ACTION_MASK ;
#if DBG_SHT
ShtpValidateList( Table, Locked ); #endif
if ( !Locked ) { ShtLockTable( Table ); }
if ( ( Table->Flags & SHT_DELETE_PENDING ) && ( Table->PendingHandle ) ) { if ( (Handle->dwUpper == Table->PendingHandle->Handle.dwUpper) && (Handle->dwLower == Table->PendingHandle->Handle.dwLower) ) { Entry = Table->PendingHandle ;
DsysAssert( Entry->Flags & SEC_HANDLE_FLAG_DELETE_PENDING );
goto FoundEntry ; } }
Scan = Table->List.Flink ;
while ( Scan != &Table->List ) { Entry = (PSEC_HANDLE_ENTRY) Scan ;
if ( Entry->Handle.dwUpper == Handle->dwUpper ) { if ( Entry->Handle.dwLower == Handle->dwLower ) { break; } }
if ( Entry->Handle.dwUpper > Handle->dwUpper ) { Entry = NULL ; break; }
Scan = Entry->List.Flink ;
Entry = NULL ; }
if ( Entry && ((Entry->Flags & SEC_HANDLE_FLAG_DELETE_PENDING) != 0 ) ) { DebugLog(( DEB_WARN, "Entry %p on list but marked delete pending\n", Entry )); Entry = NULL ; }
if ( Entry && ( Entry->HandleCount == 0 ) && ( !Checked ) ) { DebugLog(( DEB_TRACE_HANDLES, "Entry %p has handle count 0, no ref for %p:%p \n", Entry, Entry->Handle.dwUpper, Entry->Handle.dwLower ));
Entry = NULL ; }
FoundEntry :
if ( Entry ) { switch ( Action ) { case SHT_ACTION_ADDHANDLE:
Entry->HandleIssuedCount++; Entry->HandleCount++ ;
//
// Fall through to the ADDREF behavior:
//
case SHT_ACTION_ADDREF:
Entry->RefCount++;
break;
case SHT_ACTION_DELHANDLE:
if ( Entry->HandleCount ) { Entry->HandleCount-- ; } else { break; }
//
// Fall through to the DELREF behavior
//
case SHT_ACTION_DELREF: case SHT_ACTION_FORCEDEL:
Entry->RefCount -- ;
DsysAssert( Entry->RefCount >= Entry->HandleCount );
if ( ( Entry->RefCount == 0 ) || ( Action == SHT_ACTION_FORCEDEL ) ) { if ( ( Entry->Flags & SEC_HANDLE_FLAG_DELETE_PENDING ) == 0 ) { RemoveEntryList( &Entry->List );
Table->Count-- ; }
Delete = TRUE ; }
break;
case SHT_ACTION_VALIDATE: default: break;
} }
if ( !Locked ) { ShtUnlockTable( Table ); }
if ( Removed ) { *Removed = Delete ; }
#if DBG_SHT
ShtpValidateList( Table, Locked ); #endif
return Entry ;
}
//+---------------------------------------------------------------------------
//
// Function: ShtpPopHandle
//
// Synopsis: Private function for the large package. Pops a handle out of
// the table for redistribution.
//
// Arguments: [Table] --
//
// History: 3-04-97 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
PSEC_HANDLE_ENTRY ShtpPopHandle( PSMALL_HANDLE_TABLE Table ) { PLIST_ENTRY List ;
ShtLockTable( Table );
if ( !IsListEmpty( &Table->List ) ) { List = RemoveHeadList( &Table->List );
Table->Count-- ; } else { List = NULL ; }
ShtUnlockTable( Table );
#if DBG_SHT
ShtpValidateList( Table, FALSE ); #endif
return ((PSEC_HANDLE_ENTRY) List ); }
//+---------------------------------------------------------------------------
//
// Function: ShtpInsertHandle
//
// Synopsis: Worker function for lht. Inserts an existing entry into a table
//
// Arguments: [Table] --
// [Entry] --
//
// History: 3-04-97 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
VOID ShtpInsertHandle( PSMALL_HANDLE_TABLE Table, PSEC_HANDLE_ENTRY Entry ) { PLIST_ENTRY Scan ; PSEC_HANDLE_ENTRY Compare ;
ShtLockTable( Table );
Scan = Table->List.Flink ;
while ( Scan != &Table->List ) { Compare = (PSEC_HANDLE_ENTRY) Scan ;
if ( Compare->Handle.dwUpper >= Entry->Handle.dwUpper ) { break; }
Scan = Compare->List.Flink ;
Compare = NULL ;
}
InsertTailList( Scan, &Entry->List );
Table->Count++;
ShtUnlockTable( Table );
#if DBG_SHT
ShtpValidateList( Table, FALSE ); #endif
}
//+---------------------------------------------------------------------------
//
// Function: ShtAddHandle
//
// Synopsis: Add a handle to the table.
//
// Arguments: [HandleTable] --
// [Handle] --
//
// History: 3-04-97 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
BOOL ShtAddHandle( PVOID HandleTable, PSecHandle Handle, PVOID Context, ULONG Flags ) { PSMALL_HANDLE_TABLE Table ; PSEC_HANDLE_ENTRY Entry ; PSEC_HANDLE_ENTRY Compare ; PLIST_ENTRY Scan ;
Table = (PSMALL_HANDLE_TABLE) HandleTable ;
//
// Need to make whole add operation atomic
//
ShtLockTable( Table );
if ( ShtpFindHandle( Table, Handle, SHT_ACTION_ADDHANDLE | SHT_ACTION_LOCKED, NULL ) ) { ShtUnlockTable( Table );
if ( Table->Flags & HANDLE_PACKAGE_REQUIRE_UNIQUE ) { return FALSE ; }
return TRUE ; }
Entry = (PSEC_HANDLE_ENTRY) LsapAllocatePrivateHeap( sizeof( SEC_HANDLE_ENTRY ) );
if ( Entry ) { Entry->RefCount = 1; Entry->HandleCount = 1; Entry->Handle = *Handle ; Entry->Context = Context ; Entry->HandleIssuedCount = 1;
Scan = Table->List.Flink ;
while ( Scan != &Table->List ) { Compare = (PSEC_HANDLE_ENTRY) Scan ;
if ( Compare->Handle.dwUpper >= Handle->dwUpper ) { break; }
Scan = Compare->List.Flink ;
Compare = NULL ;
}
Entry->Flags = Flags ;
InsertTailList( Scan, &Entry->List );
Table->Count++;
ShtUnlockTable( Table );
#if DBG_SHT
ShtpValidateList( Table, FALSE ); #endif
return TRUE ; }
ShtUnlockTable( Table );
return FALSE ;
}
//+---------------------------------------------------------------------------
//
// Function: ShtDeleteHandle
//
// Synopsis: Deletes a handle from the table
//
// Arguments: [HandleTable] --
// [Handle] --
// [Force] --
//
// History: 3-04-97 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
BOOL ShtDeleteHandle( PVOID HandleTable, PSecHandle Handle, ULONG Options ) { PSEC_HANDLE_ENTRY Entry ; BOOL Delete ;
Entry = ShtpFindHandle( (PSMALL_HANDLE_TABLE) HandleTable, Handle, (Options & DELHANDLE_FORCE) ? SHT_ACTION_FORCEDEL : SHT_ACTION_DELHANDLE, &Delete );
if ( Entry ) { if ( Delete ) { PSMALL_HANDLE_TABLE Table = (PSMALL_HANDLE_TABLE) HandleTable ;
if ( ( Table->DeleteCallback ) && ( ( Options & DELHANDLE_NO_CALLBACK ) == 0 ) && ( ( Entry->Flags & SEC_HANDLE_FLAG_NO_CALLBACK ) == 0 ) ) { Table->DeleteCallback( &Entry->Handle, Entry->Context, Entry->HandleIssuedCount // Entry->RefCount
); }
if ( (Entry->Flags & SEC_HANDLE_FLAG_DELETE_PENDING) == 0 ) { LsapFreePrivateHeap( Entry ); }
}
return TRUE ; }
return FALSE ; }
//+---------------------------------------------------------------------------
//
// Function: ShtValidateHandle
//
// Synopsis: Validates a handle is listed in the table.
//
// Arguments: [HandleTable] --
// [Handle] --
//
// History: 3-04-97 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
BOOL ShtValidateHandle( PVOID HandleTable, PSecHandle Handle, BOOL Deref ) { PSEC_HANDLE_ENTRY Entry ; BOOL Delete = FALSE ; PSMALL_HANDLE_TABLE Table = (PSMALL_HANDLE_TABLE) HandleTable ;
Entry = ShtpFindHandle( Table, Handle, (Deref ? SHT_ACTION_DELHANDLE : SHT_ACTION_VALIDATE), &Delete );
if ( Entry ) { if ( Delete ) { if ( ( Table->DeleteCallback ) && ( ( Entry->Flags & SEC_HANDLE_FLAG_NO_CALLBACK ) == 0 ) ) { Table->DeleteCallback( &Entry->Handle, Entry->Context, Entry->HandleIssuedCount // Entry->HandleCount
); }
if ( ( Entry->Flags & SEC_HANDLE_FLAG_DELETE_PENDING ) == 0 ) { LsapFreePrivateHeap( Entry ); } } return TRUE ; } else { return FALSE ; } }
PVOID ShtRefHandle( PVOID HandleTable, PSecHandle Handle ) { PSEC_HANDLE_ENTRY Entry ;
Entry = ShtpFindHandle( (PSMALL_HANDLE_TABLE) HandleTable, Handle, SHT_ACTION_ADDREF, NULL );
return Entry ;
}
VOID ShtDerefHandleKey( PVOID HandleTable, PVOID HandleKey ) { PSMALL_HANDLE_TABLE Table = (PSMALL_HANDLE_TABLE) HandleTable ; PSEC_HANDLE_ENTRY Entry = (PSEC_HANDLE_ENTRY) HandleKey ; BOOL Delete = FALSE ;
ShtLockTable( Table );
Entry->RefCount -- ;
DsysAssert( Entry->RefCount >= Entry->HandleCount );
if ( ( Entry->Flags & SEC_HANDLE_FLAG_DELETE_PENDING ) == 0 ) { if ( Entry->RefCount == 0 ) { RemoveEntryList( &Entry->List );
Delete = TRUE ;
Table->Count-- ; } }
ShtUnlockTable( Table );
if ( Delete ) { if ( ( Table->DeleteCallback ) && ( ( Entry->Flags & SEC_HANDLE_FLAG_NO_CALLBACK ) == 0 ) ) { Table->DeleteCallback( &Entry->Handle, Entry->Context, Entry->HandleCount ); }
if ( ( Entry->Flags & SEC_HANDLE_FLAG_DELETE_PENDING ) == 0 ) { LsapFreePrivateHeap( Entry ); } }
}
//+---------------------------------------------------------------------------
//
// Function: ShtGetHandleContext
//
// Synopsis: Returns the context pointer associated with the handle
//
// Arguments: [HandleTable] --
// [Handle] --
//
// History: 8-17-98 RichardW Created
//
// Notes: Adds a reference so it can't be deleted while in use.
//
//----------------------------------------------------------------------------
PVOID ShtGetHandleContext( PVOID HandleTable, PSecHandle Handle ) { PSEC_HANDLE_ENTRY Entry ;
Entry = ShtpFindHandle( (PSMALL_HANDLE_TABLE) HandleTable, Handle, SHT_ACTION_ADDREF, NULL );
if ( Entry ) { return Entry->Context ; }
return NULL ; }
//+---------------------------------------------------------------------------
//
// Function: ShtReleaseContext
//
// Synopsis: Deref's a handle entry
//
// Arguments: [HandleTable] --
// [Handle] --
//
// History: 8-17-98 RichardW Created
//
// Notes:
//
//----------------------------------------------------------------------------
BOOL ShtReleaseContext( PVOID HandleTable, PSecHandle Handle ) { PSEC_HANDLE_ENTRY Entry ; BOOL Delete ;
Entry = ShtpFindHandle( (PSMALL_HANDLE_TABLE) HandleTable, Handle, SHT_ACTION_DELREF, &Delete );
if ( Entry ) { if ( Delete ) { PSMALL_HANDLE_TABLE Table = (PSMALL_HANDLE_TABLE) HandleTable ;
if ( ( Table->DeleteCallback ) && ( ( Entry->Flags & SEC_HANDLE_FLAG_NO_CALLBACK ) == 0 ) ) { Table->DeleteCallback( &Entry->Handle, Entry->Context, Entry->RefCount ); }
if ( ( Entry->Flags & SEC_HANDLE_FLAG_DELETE_PENDING ) == 0 ) { LsapFreePrivateHeap( Entry ); } }
return TRUE ; }
return FALSE ; }
|