1506 lines
37 KiB
C++
1506 lines
37 KiB
C++
|
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|||
|
|
|||
|
Copyright (c) 1993-2000 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
rpcssm.cxx
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
RpcS* memory package routines are implemented here.
|
|||
|
These corespond to DCE rpc_ss_* and rpc_sm_* routines.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Michael Montague (mikemon) 12-Apr-1993
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
Ryszardk Nov 30, 1993 added rpc_sm_* package,
|
|||
|
rewrote rpc_ss_* package
|
|||
|
|
|||
|
-------------------------------------------------------------------*/
|
|||
|
|
|||
|
#include <assert.h>
|
|||
|
#include <ndrp.h> // rpcndr.h and NDR_ASSERT
|
|||
|
|
|||
|
void NdrRpcDeleteAllocationContext();
|
|||
|
void ForceNdrCleanupSegIntoMemory();
|
|||
|
#include "util.hxx"
|
|||
|
#include "rpcssm.hxx"
|
|||
|
|
|||
|
|
|||
|
// =======================================================================
|
|||
|
// RpcSs Package
|
|||
|
// =======================================================================
|
|||
|
|
|||
|
// This structure is being initialized with (plain) malloc and free
|
|||
|
// by an assignement in NdrClientInitializeNew.
|
|||
|
// It is used only by the client side.
|
|||
|
// We need a pointer, too, because of a C compiler problem on Dos.
|
|||
|
|
|||
|
MALLOC_FREE_STRUCT RpcSsDefaults = { 0, 0 };
|
|||
|
MALLOC_FREE_STRUCT * pRpcSsDefaults = &RpcSsDefaults;
|
|||
|
|
|||
|
|
|||
|
EXTERN_C void NdrpSetRpcSsDefaults(RPC_CLIENT_ALLOC *pfnAlloc,
|
|||
|
RPC_CLIENT_FREE *pfnFree)
|
|||
|
{
|
|||
|
pRpcSsDefaults->pfnAllocate = pfnAlloc;
|
|||
|
pRpcSsDefaults->pfnFree = pfnFree;
|
|||
|
}
|
|||
|
|
|||
|
// These are default allocator and deallocator used by the client side
|
|||
|
// when the memory package hasn't been enabled. They map to C-runtime
|
|||
|
// malloc and free.
|
|||
|
// When the client side executes in an enabled environment, the client
|
|||
|
// doesn't use these two routines; instead, it uses the same default
|
|||
|
// allocator that the server does (NdrRpcSsDefaultAllocate/Free).
|
|||
|
// Those map into I_RpcAllocate/I_RpcFree, and those in turn map into
|
|||
|
// system Rtl* routines.
|
|||
|
|
|||
|
static void * __RPC_API
|
|||
|
DefaultAllocate (
|
|||
|
IN size_t Size
|
|||
|
)
|
|||
|
{
|
|||
|
if ( RpcSsDefaults.pfnAllocate == NULL )
|
|||
|
RpcRaiseException( RPC_X_WRONG_STUB_VERSION );
|
|||
|
|
|||
|
return( RpcSsDefaults.pfnAllocate( Size ) ) ;
|
|||
|
}
|
|||
|
|
|||
|
static void __RPC_API
|
|||
|
DefaultFree (
|
|||
|
IN void * Ptr
|
|||
|
)
|
|||
|
{
|
|||
|
if ( RpcSsDefaults.pfnFree == NULL )
|
|||
|
RpcRaiseException( RPC_X_WRONG_STUB_VERSION );
|
|||
|
|
|||
|
RpcSsDefaults.pfnFree( Ptr );
|
|||
|
}
|
|||
|
|
|||
|
// -----------------------------------------------------------------
|
|||
|
|
|||
|
|
|||
|
PALLOCATION_CONTEXT
|
|||
|
GetCreateAllocationContext (
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
The allocation information for this thread is returned. If there is
|
|||
|
no allocation information context for this thread, one gets allocated.
|
|||
|
If there is insufficient memory, an exception is raised.
|
|||
|
|
|||
|
Exceptions:
|
|||
|
|
|||
|
RPC_S_OUT_OF_MEMORY - If insufficient memory is available, this exception
|
|||
|
will be raised.
|
|||
|
|
|||
|
Notes.
|
|||
|
|
|||
|
pBlocDescr == 0 means that the memory package is disabled.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PALLOCATION_CONTEXT AllocationContext = GetAllocContext();;
|
|||
|
|
|||
|
if ( AllocationContext == 0 )
|
|||
|
{
|
|||
|
if ( NdrpPerformRpcInitialization() == RPC_S_OK )
|
|||
|
{
|
|||
|
AllocationContext = (PALLOCATION_CONTEXT)
|
|||
|
I_RpcAllocate( sizeof(ALLOCATION_CONTEXT) );
|
|||
|
}
|
|||
|
|
|||
|
if ( AllocationContext == 0 )
|
|||
|
{
|
|||
|
RpcRaiseException(RPC_S_OUT_OF_MEMORY);
|
|||
|
}
|
|||
|
|
|||
|
InitializeCriticalSection( &(AllocationContext->CriticalSection) );
|
|||
|
AllocationContext->ClientAlloc = DefaultAllocate;
|
|||
|
AllocationContext->ClientFree = DefaultFree;
|
|||
|
AllocationContext->EnableCount = 0;
|
|||
|
|
|||
|
SYSTEM_INFO SystemInfo;
|
|||
|
|
|||
|
AllocationContext->ThreadCount = 1;
|
|||
|
AllocationContext->pInitialStacks = 0;
|
|||
|
AllocationContext->pEnableStack = 0;
|
|||
|
AllocationContext->pBlockDescr = 0;
|
|||
|
GetSystemInfo( &SystemInfo );
|
|||
|
AllocationContext->PageSize = SystemInfo.dwPageSize;
|
|||
|
AllocationContext->Granularity = SystemInfo.dwAllocationGranularity;
|
|||
|
|
|||
|
SetAllocContext( AllocationContext ); // Tls
|
|||
|
}
|
|||
|
|
|||
|
return( AllocationContext );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
// -----------------------------------------------------------------
|
|||
|
|
|||
|
void *
|
|||
|
FindBlockForTheChunk(
|
|||
|
PALLOCATION_CONTEXT AllocationContext,
|
|||
|
size_t Size )
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine returns the pointer to the allocated chunk of memory.
|
|||
|
If it cannot allocate a chunk it returns NULL.
|
|||
|
This is used only in Win32 version.
|
|||
|
|
|||
|
Note:
|
|||
|
|
|||
|
This is called within the critical section.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
char * AllocationBlock;
|
|||
|
DWORD SizeToAllocate;
|
|||
|
unsigned long i, BlockSize;
|
|||
|
PALLOC_BLOCK_DESCR pDescrTemp;
|
|||
|
char * pChunk;
|
|||
|
|
|||
|
// Round the size to a multiple of 8, so that
|
|||
|
// each memory chunk is always on an aligned by 8 boundary.
|
|||
|
|
|||
|
Size = ALIGN_TO_8( Size );
|
|||
|
|
|||
|
// If the size is 0, allocate 8 bytes anyways to guarantee uniqueness
|
|||
|
// and to prevent aliasing problems.
|
|||
|
|
|||
|
if ( Size == 0 )
|
|||
|
Size = 8;
|
|||
|
|
|||
|
// See if the chunk can be allocated within an existing block.
|
|||
|
// We use the first fit algorithm to do that.
|
|||
|
|
|||
|
BlockSize = AllocationContext->PageSize;
|
|||
|
|
|||
|
if ( Size < BlockSize )
|
|||
|
{
|
|||
|
for ( i = 0; i < AllocationContext->FFIndex; i++ )
|
|||
|
{
|
|||
|
pDescrTemp = & AllocationContext->pBlockDescr[i];
|
|||
|
if ( pDescrTemp->SizeLeft >= Size )
|
|||
|
{
|
|||
|
pChunk = pDescrTemp->FirstFree;
|
|||
|
pDescrTemp->FirstFree += Size;
|
|||
|
pDescrTemp->SizeLeft -= Size;
|
|||
|
|
|||
|
#if defined( DEBUGRPC )
|
|||
|
pDescrTemp->Counter ++;
|
|||
|
#endif
|
|||
|
|
|||
|
return( pChunk );
|
|||
|
}
|
|||
|
}
|
|||
|
// Doesn't fit anywhere: allocate a new block.
|
|||
|
|
|||
|
SizeToAllocate = BlockSize;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// Size is too big to fit in leftovers.
|
|||
|
// Round it up to the block size boundary.
|
|||
|
|
|||
|
size_t Alignment = BlockSize - 1;
|
|||
|
|
|||
|
SizeToAllocate = (Size + Alignment) & ~Alignment;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Being here means a need to allocate a new block of pages.
|
|||
|
//
|
|||
|
|
|||
|
if ( AllocationContext->FFIndex >= AllocationContext->DescrSize )
|
|||
|
{
|
|||
|
// need to reallocate the array of descriptors first.
|
|||
|
|
|||
|
size_t NewDescrSize = AllocationContext->DescrSize +
|
|||
|
DESCR_ARRAY_INCR;
|
|||
|
pDescrTemp = (PALLOC_BLOCK_DESCR)
|
|||
|
I_RpcAllocate( NewDescrSize * sizeof( ALLOC_BLOCK_DESCR ));
|
|||
|
if ( pDescrTemp == 0 )
|
|||
|
{
|
|||
|
return( NULL );
|
|||
|
}
|
|||
|
|
|||
|
RpcpMemoryCopy( pDescrTemp,
|
|||
|
AllocationContext->pBlockDescr,
|
|||
|
(size_t)(AllocationContext->FFIndex
|
|||
|
* sizeof( ALLOC_BLOCK_DESCR )) );
|
|||
|
|
|||
|
if ( AllocationContext->pBlockDescr !=
|
|||
|
AllocationContext->pInitialStacks->DescrStack )
|
|||
|
I_RpcFree( AllocationContext->pBlockDescr );
|
|||
|
|
|||
|
AllocationContext->pBlockDescr = pDescrTemp;
|
|||
|
AllocationContext->DescrSize = NewDescrSize;
|
|||
|
}
|
|||
|
|
|||
|
// Now allocate the new block.
|
|||
|
|
|||
|
AllocationBlock = (char *) VirtualAlloc( NULL, // new pages
|
|||
|
SizeToAllocate,
|
|||
|
MEM_COMMIT,
|
|||
|
PAGE_READWRITE );
|
|||
|
if ( AllocationBlock == 0 )
|
|||
|
{
|
|||
|
return( NULL );
|
|||
|
}
|
|||
|
|
|||
|
NDR_ASSERT( ((ULONG_PTR)AllocationBlock & 0x7) == 0,
|
|||
|
"buffer alignment error at allocation time" );
|
|||
|
|
|||
|
pDescrTemp = & AllocationContext->pBlockDescr[ AllocationContext->FFIndex ];
|
|||
|
pDescrTemp->AllocationBlock = AllocationBlock;
|
|||
|
pDescrTemp->FirstFree = AllocationBlock + Size;
|
|||
|
pDescrTemp->SizeLeft = SizeToAllocate - Size;
|
|||
|
|
|||
|
#if defined( DEBUGRPC )
|
|||
|
pDescrTemp->Counter = 1;
|
|||
|
#endif
|
|||
|
|
|||
|
AllocationContext->FFIndex++;
|
|||
|
|
|||
|
return( AllocationBlock );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void * RPC_ENTRY
|
|||
|
RpcSsAllocate (
|
|||
|
IN size_t Size
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Allocate memory within the allocation context fot the thread. A call to
|
|||
|
RpcSsEnableAllocate sets up an allocation context for the calling thread.
|
|||
|
When the application (and/or the stubs) call RpcSsDisableAllocate,
|
|||
|
any memory allocated by RpcSsAllocate in the context which has not been
|
|||
|
freed (by RpcSsFree) will be freed, and the context will be freed.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Size - Supplies the amount of memory required in bytes.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
A pointer to the allocated block of memory will be returned.
|
|||
|
|
|||
|
Note:
|
|||
|
|
|||
|
This is Win32 version.
|
|||
|
|
|||
|
Exceptions:
|
|||
|
|
|||
|
RPC_S_OUT_OF_MEMORY - If insufficient memory is available, this exception
|
|||
|
will be raised.
|
|||
|
RPC_S_INVALID_ARG - If no allocation context yet.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
void * AllocatedChunk = 0;
|
|||
|
PALLOCATION_CONTEXT AllocationContext = GetAllocContext();
|
|||
|
|
|||
|
if ( AllocationContext == 0 )
|
|||
|
{
|
|||
|
RpcRaiseException( RPC_S_INVALID_ARG );
|
|||
|
}
|
|||
|
|
|||
|
EnterCriticalSection( &(AllocationContext->CriticalSection) );
|
|||
|
|
|||
|
if ( AllocationContext->EnableCount )
|
|||
|
AllocatedChunk = FindBlockForTheChunk( AllocationContext, Size );
|
|||
|
|
|||
|
LeaveCriticalSection( &(AllocationContext->CriticalSection) );
|
|||
|
|
|||
|
if ( AllocatedChunk == NULL )
|
|||
|
{
|
|||
|
RpcRaiseException(RPC_S_OUT_OF_MEMORY);
|
|||
|
}
|
|||
|
|
|||
|
return( AllocatedChunk );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
static void
|
|||
|
NdrpReleaseMemory(
|
|||
|
PALLOCATION_CONTEXT AllocationContext
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Releases all the memory related to the package except for the
|
|||
|
control block itself.
|
|||
|
|
|||
|
Note:
|
|||
|
|
|||
|
This is Win32 version and is called from the critical section
|
|||
|
in disable allocate and set thread.
|
|||
|
--*/
|
|||
|
{
|
|||
|
unsigned long i;
|
|||
|
|
|||
|
for ( i = 0; i < AllocationContext->FFIndex; i++ )
|
|||
|
{
|
|||
|
VirtualFree( AllocationContext->pBlockDescr[i].AllocationBlock,
|
|||
|
0, // free all of it
|
|||
|
MEM_RELEASE );
|
|||
|
}
|
|||
|
I_RpcFree( AllocationContext->pInitialStacks );
|
|||
|
if ( AllocationContext->pEnableStack !=
|
|||
|
AllocationContext->pInitialStacks->EnableStack )
|
|||
|
I_RpcFree( AllocationContext->pEnableStack );
|
|||
|
if ( AllocationContext->pBlockDescr !=
|
|||
|
AllocationContext->pInitialStacks->DescrStack )
|
|||
|
I_RpcFree( AllocationContext->pBlockDescr );
|
|||
|
|
|||
|
AllocationContext->pInitialStacks = 0;
|
|||
|
AllocationContext->pEnableStack = 0;
|
|||
|
AllocationContext->StackMax = 0;
|
|||
|
AllocationContext->StackTop = 0;
|
|||
|
AllocationContext->pBlockDescr = 0;
|
|||
|
AllocationContext->DescrSize = 0;
|
|||
|
AllocationContext->FFIndex = 0;
|
|||
|
AllocationContext->ClientAlloc = DefaultAllocate;
|
|||
|
AllocationContext->ClientFree = DefaultFree;
|
|||
|
|
|||
|
NDR_ASSERT( AllocationContext->ThreadCount, "when relesing all memory" );
|
|||
|
AllocationContext->ThreadCount--;
|
|||
|
}
|
|||
|
|
|||
|
static void
|
|||
|
NdrpDisableAllocate(
|
|||
|
BOOL fCalledFromStub
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Multiple enable/disable are allowed and the EnableCount is used to keep
|
|||
|
track of it.
|
|||
|
We disable only when counter comes back to 0.
|
|||
|
We ignore too many disables.
|
|||
|
|
|||
|
This routine will free memory associated with the allocation context
|
|||
|
for this thread as well as the allocation context.
|
|||
|
|
|||
|
However, the routine frees only blocks allocated with the default
|
|||
|
allocator. Other blocks are considered to be allocated
|
|||
|
with a swapped/set user allocator and so we leave them alone.
|
|||
|
Allocation context gets freed when process detaches.
|
|||
|
|
|||
|
Note:
|
|||
|
|
|||
|
This is Win32 version.
|
|||
|
--*/
|
|||
|
{
|
|||
|
PALLOCATION_CONTEXT AllocationContext = GetAllocContext();
|
|||
|
unsigned long NewLevel;
|
|||
|
BOOL fTooManyDisables = FALSE;
|
|||
|
BOOL fLastThreadGoingAway = FALSE;
|
|||
|
|
|||
|
if ( AllocationContext == 0 )
|
|||
|
return;
|
|||
|
|
|||
|
EnterCriticalSection( &(AllocationContext->CriticalSection) );
|
|||
|
|
|||
|
if ( fCalledFromStub )
|
|||
|
{
|
|||
|
NDR_ASSERT( AllocationContext->StackTop, "mismatch in stub calls" );
|
|||
|
NewLevel = AllocationContext
|
|||
|
->pEnableStack[ -- AllocationContext->StackTop ];
|
|||
|
}
|
|||
|
else
|
|||
|
NewLevel = AllocationContext->EnableCount - 1;
|
|||
|
|
|||
|
// We are forcing the EnableCount to get the value from the EnableStack,
|
|||
|
// when possible.
|
|||
|
|
|||
|
if ( AllocationContext->EnableCount )
|
|||
|
AllocationContext->EnableCount = NewLevel;
|
|||
|
else
|
|||
|
{
|
|||
|
// doesn't fall below zero.
|
|||
|
|
|||
|
fTooManyDisables = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
if ( AllocationContext->EnableCount == 0 )
|
|||
|
{
|
|||
|
// First free everything except the control block.
|
|||
|
|
|||
|
if ( !fTooManyDisables )
|
|||
|
NdrpReleaseMemory( AllocationContext );
|
|||
|
|
|||
|
// Now see if we need to free the context itself.
|
|||
|
|
|||
|
// Because of the thread reusage in the runtime, and consequently,
|
|||
|
// some threads hanging around forever, we need to dispose
|
|||
|
// of this, even though it costs a new allocation later.
|
|||
|
|
|||
|
if ( AllocationContext->ThreadCount == 0 )
|
|||
|
{
|
|||
|
fLastThreadGoingAway = TRUE;
|
|||
|
SetAllocContext( NULL );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
LeaveCriticalSection( &(AllocationContext->CriticalSection) );
|
|||
|
|
|||
|
if ( fLastThreadGoingAway)
|
|||
|
{
|
|||
|
DeleteCriticalSection( &(AllocationContext->CriticalSection) );
|
|||
|
I_RpcFree( AllocationContext );
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
void RPC_ENTRY
|
|||
|
RpcSsDisableAllocate (
|
|||
|
void
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
See the description of NdrpDisableAllocate.
|
|||
|
|
|||
|
Note:
|
|||
|
|
|||
|
This is Win32 version.
|
|||
|
--*/
|
|||
|
{
|
|||
|
NdrpDisableAllocate( FALSE );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
static void
|
|||
|
NdrpEnableAllocate (
|
|||
|
BOOL fCalledFromStub
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine will set up an allocation context for this thread.
|
|||
|
|
|||
|
Note:
|
|||
|
|
|||
|
The behavior is such that it is valid to call EnableAllocate
|
|||
|
several times in a row without calling DisableAllocate.
|
|||
|
The number to calls to Disable has to much that of Enable.
|
|||
|
|
|||
|
This is Win32 version.
|
|||
|
|
|||
|
Exceptions:
|
|||
|
|
|||
|
RPC_S_OUT_OF_MEMORY - If insufficient memory is available, this exception
|
|||
|
will be raised.
|
|||
|
--*/
|
|||
|
{
|
|||
|
PALLOCATION_CONTEXT AllocationContext = GetCreateAllocationContext();
|
|||
|
int Successful = 1;
|
|||
|
|
|||
|
EnterCriticalSection( &(AllocationContext->CriticalSection) );
|
|||
|
|
|||
|
if ( AllocationContext->EnableCount == 0 )
|
|||
|
{
|
|||
|
AllocationContext->pInitialStacks = (INIT_STACKS_BLOCK *)
|
|||
|
I_RpcAllocate( sizeof( INIT_STACKS_BLOCK ) );
|
|||
|
|
|||
|
if ( AllocationContext->pInitialStacks )
|
|||
|
{
|
|||
|
AllocationContext->pEnableStack =
|
|||
|
AllocationContext->pInitialStacks->EnableStack;
|
|||
|
AllocationContext->StackMax = ENABLE_STACK_SIZE;
|
|||
|
AllocationContext->StackTop = 0;
|
|||
|
|
|||
|
AllocationContext->pBlockDescr =
|
|||
|
AllocationContext->pInitialStacks->DescrStack;
|
|||
|
AllocationContext->DescrSize = DESCR_ARRAY_SIZE;
|
|||
|
AllocationContext->FFIndex = 0;
|
|||
|
|
|||
|
AllocationContext->ClientAlloc = RpcSsAllocate;
|
|||
|
AllocationContext->ClientFree = RpcSsFree;
|
|||
|
}
|
|||
|
else
|
|||
|
Successful = 0;
|
|||
|
}
|
|||
|
|
|||
|
if ( Successful )
|
|||
|
{
|
|||
|
if ( fCalledFromStub )
|
|||
|
{
|
|||
|
// Push the current enable level on the EnableStack to have
|
|||
|
// a point to come back when disabling from the server stub.
|
|||
|
|
|||
|
if ( AllocationContext->StackTop >= AllocationContext->StackMax )
|
|||
|
{
|
|||
|
// Need to reallocate the EnableStack first.
|
|||
|
|
|||
|
ulong NewMax;
|
|||
|
ulong * pStackTemp;
|
|||
|
|
|||
|
NewMax = AllocationContext->StackMax + ENABLE_STACK_SIZE;
|
|||
|
pStackTemp = (ulong *) I_RpcAllocate( NewMax * sizeof(ulong) );
|
|||
|
|
|||
|
if ( pStackTemp )
|
|||
|
{
|
|||
|
RpcpMemoryCopy( pStackTemp,
|
|||
|
AllocationContext->pEnableStack,
|
|||
|
AllocationContext->StackMax * sizeof(ulong) );
|
|||
|
if ( AllocationContext->pEnableStack !=
|
|||
|
AllocationContext->pInitialStacks->EnableStack )
|
|||
|
I_RpcFree( AllocationContext->pEnableStack );
|
|||
|
|
|||
|
AllocationContext->pEnableStack = pStackTemp;
|
|||
|
AllocationContext->StackMax = NewMax;
|
|||
|
}
|
|||
|
else
|
|||
|
Successful = 0;
|
|||
|
}
|
|||
|
|
|||
|
if ( Successful )
|
|||
|
AllocationContext->pEnableStack[ AllocationContext->StackTop++ ]
|
|||
|
= AllocationContext->EnableCount;
|
|||
|
else
|
|||
|
if ( AllocationContext->EnableCount == 0 )
|
|||
|
{
|
|||
|
// just allocated the stuff ..
|
|||
|
I_RpcFree( AllocationContext->pInitialStacks );
|
|||
|
AllocationContext->pInitialStacks = 0;
|
|||
|
AllocationContext->pEnableStack = 0;
|
|||
|
AllocationContext->pBlockDescr = 0;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Increment the counter to a new level.
|
|||
|
|
|||
|
if ( Successful )
|
|||
|
{
|
|||
|
AllocationContext->EnableCount++;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
LeaveCriticalSection( &(AllocationContext->CriticalSection) );
|
|||
|
|
|||
|
if ( ! Successful )
|
|||
|
{
|
|||
|
RpcRaiseException(RPC_S_OUT_OF_MEMORY);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void RPC_ENTRY
|
|||
|
RpcSsEnableAllocate (
|
|||
|
void
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine will set up an allocation context for this thread.
|
|||
|
|
|||
|
Note:
|
|||
|
|
|||
|
The behavior is such that it is valid to call EnableAllocate
|
|||
|
several times in a row without calling DisableAllocate.
|
|||
|
The number to calls to Disable should much that of Enable.
|
|||
|
|
|||
|
This is Win32 version.
|
|||
|
|
|||
|
Exceptions:
|
|||
|
|
|||
|
RPC_S_OUT_OF_MEMORY - If insufficient memory is available, this exception
|
|||
|
will be raised.
|
|||
|
--*/
|
|||
|
{
|
|||
|
NdrpEnableAllocate( FALSE );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void RPC_ENTRY
|
|||
|
RpcSsFree (
|
|||
|
IN void * NodeToFree
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
When a block of memory allocated by RpcSsAllocate is no longer needed,
|
|||
|
it can be freed using RpcSsFree.
|
|||
|
Actually, for win32 we do nothing
|
|||
|
- all blocks will be freed at the Disable time as we want speed.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
NodeToFree - Supplies the block of memory, allocated by RpcSsAllocate, to
|
|||
|
be freed.
|
|||
|
|
|||
|
Note:
|
|||
|
|
|||
|
This is Win32 version.
|
|||
|
--*/
|
|||
|
{
|
|||
|
PALLOCATION_CONTEXT AllocationContext = GetAllocContext();
|
|||
|
|
|||
|
if ( AllocationContext == 0 )
|
|||
|
{
|
|||
|
#if defined( DEBUGRPC )
|
|||
|
RpcRaiseException( RPC_S_INVALID_ARG );
|
|||
|
#else
|
|||
|
return;
|
|||
|
#endif
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
// -----------------------------------------------------------------
|
|||
|
|
|||
|
|
|||
|
RPC_SS_THREAD_HANDLE RPC_ENTRY
|
|||
|
RpcSsGetThreadHandle (
|
|||
|
void
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
A handle to the allocation context for this thread will be returned.
|
|||
|
This makes it possible for two threads to share an allocation context.
|
|||
|
See RpcSsSetThreadHandle as well.
|
|||
|
|
|||
|
!= NULL - only when the environement is actually enabled.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PALLOCATION_CONTEXT AllocationContext = GetAllocContext();
|
|||
|
RPC_SS_THREAD_HANDLE Handle = 0;
|
|||
|
|
|||
|
if ( AllocationContext == 0 )
|
|||
|
return( 0 );
|
|||
|
|
|||
|
EnterCriticalSection( &(AllocationContext->CriticalSection) );
|
|||
|
|
|||
|
// Check if the memory environement is enabled.
|
|||
|
|
|||
|
if ( AllocationContext->EnableCount > 0 )
|
|||
|
Handle = AllocationContext;
|
|||
|
|
|||
|
LeaveCriticalSection( &(AllocationContext->CriticalSection) );
|
|||
|
|
|||
|
return( Handle );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void RPC_ENTRY
|
|||
|
RpcSsSetClientAllocFree (
|
|||
|
IN RPC_CLIENT_ALLOC * ClientAlloc,
|
|||
|
IN RPC_CLIENT_FREE * ClientFree
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
The routines to be used by the client to allocate and free memory can
|
|||
|
be set using this routine. See also RpcSsSwapClientAllocFree.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ClientAlloc - Supplies the routine to use to allocate memory.
|
|||
|
ClientFree - Supplies the routine to use to free memory.
|
|||
|
|
|||
|
Exceptions:
|
|||
|
|
|||
|
RPC_S_OUT_OF_MEMORY - If insufficient memory is available, this exception
|
|||
|
will be raised.
|
|||
|
|
|||
|
Note. Back door to enable.
|
|||
|
|
|||
|
DCE (DEC's intrepretation of DCE) has this weird requirement that
|
|||
|
the user can set (or swap in) his private allocator pair without first
|
|||
|
enabling the package. This makes it possible for the client side stub
|
|||
|
to use a private allocator (instead of malloc/free (in osf mode)) to
|
|||
|
allocate when unmarshalling.
|
|||
|
|
|||
|
However, that doesn't enable the package. So, issuing a regular API like
|
|||
|
RpcSsAllocate still fails.
|
|||
|
|
|||
|
The expected behavior is to Enable the package, set or swap private
|
|||
|
allocators and then RpcSsAllocate is a valid call.
|
|||
|
|
|||
|
This has some impact on the disable behavior. The implementation allows
|
|||
|
for multiple enables and disables. To prevent leaking/passing on an
|
|||
|
non-empty memory context with a thread when the thread is reused,
|
|||
|
there is a control mechanism (the enable stack) that makes sure that
|
|||
|
disbling from the stubs resets the enable level to the one at the
|
|||
|
enable time.
|
|||
|
|
|||
|
Now, when the (server) stub issues enable, the corresponding disable
|
|||
|
will do the right thing, regardless of what the user might have messed up.
|
|||
|
If there weren't eanough disables, it will free everything; if there were
|
|||
|
too many disables, it would quietly do nothing.
|
|||
|
|
|||
|
When the user issues an enable, the matching disable will clean up
|
|||
|
everything. If there is insufficient number of disable call on the client,
|
|||
|
there is a leak and we cannot do anything about it. Too many calls are ok.
|
|||
|
|
|||
|
Now at last. If the user issues set/swap, an (empty) context is created
|
|||
|
with the disabled state. If the package has never been enabled, this empty
|
|||
|
context won't be deleted by a disable (this would be a disable too many).
|
|||
|
This is harmul both on client and server so I leave it as it is.
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PALLOCATION_CONTEXT AllocationContext = GetCreateAllocationContext();
|
|||
|
|
|||
|
// The only reason we enter the critical section here is to keep
|
|||
|
// the pair consistent.
|
|||
|
|
|||
|
EnterCriticalSection( &(AllocationContext->CriticalSection) );
|
|||
|
|
|||
|
AllocationContext->ClientAlloc = ClientAlloc;
|
|||
|
AllocationContext->ClientFree = ClientFree;
|
|||
|
|
|||
|
LeaveCriticalSection( &(AllocationContext->CriticalSection) );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void RPC_ENTRY
|
|||
|
RpcSsSetThreadHandle (
|
|||
|
IN RPC_SS_THREAD_HANDLE Id
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
The allocation context for this thread will set to be the supplied
|
|||
|
allocation context.
|
|||
|
For 32bit environment, the ThreadReCount is updated.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Id - Supplies the allocation context to use for this thread.
|
|||
|
|
|||
|
Exceptions:
|
|||
|
|
|||
|
RPC_S_OUT_OF_MEMORY - If insufficient memory is available, this exception
|
|||
|
will be raised.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
// This is 32bit and 64b code.
|
|||
|
|
|||
|
// DCE doesn't really specify any means to support some kind of thread
|
|||
|
// ref counting and so additional semantics has been defined for this
|
|||
|
// API.
|
|||
|
// In order to define some orderly behavior for the apps passing
|
|||
|
// thread handles around, we keep track of how many threads can
|
|||
|
// access an allocation context. For an app to be clean, each thread
|
|||
|
// that issues set call(s) with non-zero argument should signal it's
|
|||
|
// done with a single set call with 0.
|
|||
|
|
|||
|
// The ThreadCount has a special flavor here, which is to
|
|||
|
// count the threads that can access the context, not the references
|
|||
|
// in the sense of set calls.
|
|||
|
// The original thread doesn't issue a set but we still have to
|
|||
|
// account for it. So we start the ThreadCount with 1, and then
|
|||
|
// the last disable (the one that frees the memory) decrements the count.
|
|||
|
// Which means that the thread issuing the last disable effectively
|
|||
|
// does a set to zero at the same time.
|
|||
|
|
|||
|
// The rules below support decrementing the ThreadCount by means
|
|||
|
// of calling the routine with thread id == 0, or with thread id being
|
|||
|
// different from the current one.
|
|||
|
// If this happens to be the call that would remove the last chance
|
|||
|
// to reference the context, we force to free everything, including
|
|||
|
// the control block.
|
|||
|
// In other words, set 0 on the last thread does the disable.
|
|||
|
|
|||
|
|
|||
|
PALLOCATION_CONTEXT pOldContext = GetAllocContext();
|
|||
|
PALLOCATION_CONTEXT pNewContext = (PALLOCATION_CONTEXT) Id;
|
|||
|
|
|||
|
if ( pOldContext != pNewContext )
|
|||
|
{
|
|||
|
if ( pOldContext )
|
|||
|
{
|
|||
|
BOOL fLastThreadGoingAway = FALSE;
|
|||
|
|
|||
|
EnterCriticalSection( &(pOldContext->CriticalSection) );
|
|||
|
|
|||
|
if ( pOldContext->ThreadCount == 1 )
|
|||
|
{
|
|||
|
// delete the memory and decrease the ref count
|
|||
|
|
|||
|
NdrpReleaseMemory( pOldContext );
|
|||
|
|
|||
|
fLastThreadGoingAway = TRUE;
|
|||
|
SetAllocContext( NULL );
|
|||
|
}
|
|||
|
|
|||
|
LeaveCriticalSection( &(pOldContext->CriticalSection) );
|
|||
|
|
|||
|
if ( fLastThreadGoingAway)
|
|||
|
{
|
|||
|
DeleteCriticalSection( &(pOldContext->CriticalSection) );
|
|||
|
I_RpcFree( pOldContext );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( pNewContext )
|
|||
|
{
|
|||
|
EnterCriticalSection( &(pNewContext->CriticalSection) );
|
|||
|
pNewContext->ThreadCount++;
|
|||
|
LeaveCriticalSection( &(pNewContext->CriticalSection) );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
SetAllocContext( pNewContext );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void RPC_ENTRY
|
|||
|
RpcSsSwapClientAllocFree (
|
|||
|
IN RPC_CLIENT_ALLOC * ClientAlloc,
|
|||
|
IN RPC_CLIENT_FREE * ClientFree,
|
|||
|
OUT RPC_CLIENT_ALLOC * * OldClientAlloc,
|
|||
|
OUT RPC_CLIENT_FREE * * OldClientFree
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
The routines to be used by the client to allocate and free memory can
|
|||
|
be set using this routine. The previous values of these routines will
|
|||
|
be returned. See also RpcSsSetClientAllocFree.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ClientAlloc - Supplies the routine to use to allocate memory.
|
|||
|
ClientFree - Supplies the routine to use to free memory.
|
|||
|
OldClientAlloc - Returns the old value of the client allocator.
|
|||
|
OldClientFree - Returns the old value of the client deallocator.
|
|||
|
|
|||
|
Exceptions:
|
|||
|
|
|||
|
RPC_S_OUT_OF_MEMORY - If insufficient memory is available, this exception
|
|||
|
will be raised.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PALLOCATION_CONTEXT AllocationContext = GetCreateAllocationContext();
|
|||
|
|
|||
|
// The only reason we enter the critical section here is to keep
|
|||
|
// the pairs consistent.
|
|||
|
|
|||
|
EnterCriticalSection( &(AllocationContext->CriticalSection) );
|
|||
|
|
|||
|
*OldClientAlloc = AllocationContext->ClientAlloc;
|
|||
|
*OldClientFree = AllocationContext->ClientFree;
|
|||
|
AllocationContext->ClientAlloc = ClientAlloc;
|
|||
|
AllocationContext->ClientFree = ClientFree;
|
|||
|
|
|||
|
LeaveCriticalSection( &(AllocationContext->CriticalSection) );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/*++ -----------------------------------------------------------------------
|
|||
|
//
|
|||
|
// RpcSm* functions are wrappers over RpcSs*
|
|||
|
//
|
|||
|
// What was earlier: a hen or an egg?
|
|||
|
// We wrap RpcSm* over RpcSs* because RpcSs* are a basic staple for stubs
|
|||
|
// and so this makes the critical path shorter.
|
|||
|
// Admittedly, RpcSm* take then longer than they could.
|
|||
|
//
|
|||
|
--*/
|
|||
|
|
|||
|
void * RPC_ENTRY
|
|||
|
RpcSmAllocate (
|
|||
|
IN size_t Size,
|
|||
|
OUT RPC_STATUS * pStatus
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Same as RpcSsAllocate, except that this one returns an error code,
|
|||
|
as opposed to raising an exception.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Size - Supplies the amount of memory required in bytes.
|
|||
|
pStatus - Returns an error code:
|
|||
|
RPC_S_OK or RPC_S_OUT_OF_MEMORY
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
A pointer to the allocated block of memory or NULL will be returned.
|
|||
|
|
|||
|
Exceptions:
|
|||
|
|
|||
|
This routine catches exceptions and returns an error code.
|
|||
|
--*/
|
|||
|
{
|
|||
|
void * AllocatedNode = 0;
|
|||
|
RpcTryExcept
|
|||
|
{
|
|||
|
AllocatedNode = RpcSsAllocate( Size );
|
|||
|
*pStatus = RPC_S_OK;
|
|||
|
}
|
|||
|
RpcExcept(1)
|
|||
|
{
|
|||
|
*pStatus = RpcExceptionCode();
|
|||
|
}
|
|||
|
RpcEndExcept
|
|||
|
return( AllocatedNode );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS RPC_ENTRY
|
|||
|
RpcSmClientFree (
|
|||
|
IN void * pNodeToFree
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Same as RpcSsClientFree, except that this one returns an error code,
|
|||
|
as opposed to raising an exception.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pNodeToFree - a memory chunk to free
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
error code - RPC_S_OK or exception code
|
|||
|
|
|||
|
Exceptions:
|
|||
|
|
|||
|
This routine catches exceptions and returns an error code.
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_STATUS Status = RPC_S_OK;
|
|||
|
RpcTryExcept
|
|||
|
{
|
|||
|
NdrRpcSmClientFree( pNodeToFree );
|
|||
|
}
|
|||
|
RpcExcept(1)
|
|||
|
{
|
|||
|
Status = RpcExceptionCode();
|
|||
|
}
|
|||
|
RpcEndExcept
|
|||
|
|
|||
|
return( Status );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS RPC_ENTRY
|
|||
|
RpcSmDisableAllocate (
|
|||
|
void
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Same as RpcSsDisableAllocate, except that this one returns an error code,
|
|||
|
as opposed to raising an exception.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
error code - RPC_S_OK or exception code
|
|||
|
|
|||
|
Exceptions:
|
|||
|
|
|||
|
Exceptions are catched and an error code is returned.
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_STATUS Status = RPC_S_OK;
|
|||
|
RpcTryExcept
|
|||
|
{
|
|||
|
RpcSsDisableAllocate();
|
|||
|
}
|
|||
|
RpcExcept(1)
|
|||
|
{
|
|||
|
Status = RpcExceptionCode();
|
|||
|
}
|
|||
|
RpcEndExcept
|
|||
|
return( Status );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS RPC_ENTRY
|
|||
|
RpcSmDestroyClientContext (
|
|||
|
IN void * * pContextHandle
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Frees the memory related to unused context handle.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ContextHandle - a context handle to be destroyed
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
error code - RPC_S_OK or exception code
|
|||
|
|
|||
|
Exceptions:
|
|||
|
|
|||
|
This routine catches exceptions and returns an error code.
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_STATUS Status = RPC_S_OK;
|
|||
|
RpcTryExcept
|
|||
|
{
|
|||
|
RpcSsDestroyClientContext( pContextHandle );
|
|||
|
}
|
|||
|
RpcExcept(1)
|
|||
|
{
|
|||
|
Status = RpcExceptionCode();
|
|||
|
}
|
|||
|
RpcEndExcept
|
|||
|
|
|||
|
return( Status );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS RPC_ENTRY
|
|||
|
RpcSmEnableAllocate (
|
|||
|
void
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Same as RpcSsEnableAllocate, except that this one returns an error code,
|
|||
|
as opposed to raising an exception.
|
|||
|
|
|||
|
Exceptions:
|
|||
|
|
|||
|
Exceptions are catched and an error code is returned.
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_STATUS Status = RPC_S_OK;
|
|||
|
RpcTryExcept
|
|||
|
{
|
|||
|
RpcSsEnableAllocate();
|
|||
|
}
|
|||
|
RpcExcept(1)
|
|||
|
{
|
|||
|
Status = RpcExceptionCode();
|
|||
|
}
|
|||
|
RpcEndExcept
|
|||
|
return( Status );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS RPC_ENTRY
|
|||
|
RpcSmFree (
|
|||
|
IN void * NodeToFree
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Same as RpcSsFree, except that this one returns an error code,
|
|||
|
as opposed to raising an exception.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
NodeToFree - Supplies the block of memory, allocated by RpcSmAllocate, to
|
|||
|
be freed.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_STATUS Status = RPC_S_OK;
|
|||
|
RpcTryExcept
|
|||
|
{
|
|||
|
RpcSsFree( NodeToFree );
|
|||
|
}
|
|||
|
RpcExcept(1)
|
|||
|
{
|
|||
|
Status = RpcExceptionCode();
|
|||
|
}
|
|||
|
RpcEndExcept
|
|||
|
return( Status );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_SS_THREAD_HANDLE RPC_ENTRY
|
|||
|
RpcSmGetThreadHandle (
|
|||
|
OUT RPC_STATUS * pStatus
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pStatus - error code
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Same as RpcSsGetThreadHandle, except that this one returns an error code,
|
|||
|
as opposed to raising an exception.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_SS_THREAD_HANDLE Handle = 0;
|
|||
|
*pStatus = RPC_S_OK;
|
|||
|
RpcTryExcept
|
|||
|
{
|
|||
|
Handle = RpcSsGetThreadHandle();
|
|||
|
}
|
|||
|
RpcExcept(1)
|
|||
|
{
|
|||
|
*pStatus = RpcExceptionCode();
|
|||
|
}
|
|||
|
RpcEndExcept
|
|||
|
return( Handle );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS RPC_ENTRY
|
|||
|
RpcSmSetClientAllocFree (
|
|||
|
IN RPC_CLIENT_ALLOC * ClientAlloc,
|
|||
|
IN RPC_CLIENT_FREE * ClientFree
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Same as RpcSsSetClientAllocFree, except that this one returns an error code,
|
|||
|
as opposed to raising an exception.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ClientAlloc - Supplies the routine to use to allocate memory.
|
|||
|
ClientFree - Supplies the routine to use to free memory.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
error code - RPC_S_OK or exception code
|
|||
|
|
|||
|
Exceptions:
|
|||
|
|
|||
|
Exceptions are catched and an error code is returned.
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_STATUS Status = RPC_S_OK;
|
|||
|
RpcTryExcept
|
|||
|
{
|
|||
|
RpcSsSetClientAllocFree( ClientAlloc, ClientFree );
|
|||
|
}
|
|||
|
RpcExcept(1)
|
|||
|
{
|
|||
|
Status = RpcExceptionCode();
|
|||
|
}
|
|||
|
RpcEndExcept
|
|||
|
return( Status );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS RPC_ENTRY
|
|||
|
RpcSmSetThreadHandle (
|
|||
|
IN RPC_SS_THREAD_HANDLE Id
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Same as RpcSsSetThreadHandle, except that this one returns an error code,
|
|||
|
as opposed to raising an exception.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Id - Supplies the allocation context to use for this thread.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
error code - RPC_S_OK or exception code (RPC_S_OUT_OF_MEMORY)
|
|||
|
|
|||
|
Exceptions:
|
|||
|
|
|||
|
Exceptions are catched and an error code is returned.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_STATUS Status = RPC_S_OK;
|
|||
|
RpcTryExcept
|
|||
|
{
|
|||
|
RpcSsSetThreadHandle( Id );
|
|||
|
}
|
|||
|
RpcExcept(1)
|
|||
|
{
|
|||
|
Status = RpcExceptionCode();
|
|||
|
}
|
|||
|
RpcEndExcept
|
|||
|
return( Status );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RPC_STATUS RPC_ENTRY
|
|||
|
RpcSmSwapClientAllocFree (
|
|||
|
IN RPC_CLIENT_ALLOC * ClientAlloc,
|
|||
|
IN RPC_CLIENT_FREE * ClientFree,
|
|||
|
OUT RPC_CLIENT_ALLOC * * OldClientAlloc,
|
|||
|
OUT RPC_CLIENT_FREE * * OldClientFree
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Same as RpcSsSwapClientAllocFree, except that this one returns an error
|
|||
|
code, as opposed to raising an exception.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ClientAlloc - Supplies the routine to use to allocate memory.
|
|||
|
ClientFree - Supplies the routine to use to free memory.
|
|||
|
OldClientAlloc - Returns the old value of the client allocator.
|
|||
|
OldClientFree - Returns the old value of the client deallocator.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
error code - RPC_S_OK or exception code (RPC_S_OUT_OF_MEMORY)
|
|||
|
|
|||
|
Exceptions:
|
|||
|
|
|||
|
Exceptions are catched and an error code is returned.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
RPC_STATUS Status = RPC_S_OK;
|
|||
|
RpcTryExcept
|
|||
|
{
|
|||
|
RpcSsSwapClientAllocFree( ClientAlloc,
|
|||
|
ClientFree,
|
|||
|
OldClientAlloc,
|
|||
|
OldClientFree );
|
|||
|
}
|
|||
|
RpcExcept(1)
|
|||
|
{
|
|||
|
Status = RpcExceptionCode();
|
|||
|
}
|
|||
|
RpcEndExcept
|
|||
|
return( Status );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
// =======================================================================
|
|||
|
// Package initialization
|
|||
|
// =======================================================================
|
|||
|
|
|||
|
// default: win32 now
|
|||
|
|
|||
|
|
|||
|
DWORD RpcAllocTlsIndex = 0xFFFFFFFF;
|
|||
|
|
|||
|
PALLOCATION_CONTEXT
|
|||
|
GetAllocContext (
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
The allocation context pointer for this thread will be returned. Use
|
|||
|
SetAllocContext to set the allocation context pointer for this thread.
|
|||
|
If GetAllocContext is called before SetAllocContext has been called, zero
|
|||
|
will be returned.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
if (RpcAllocTlsIndex == 0xFFFFFFFF)
|
|||
|
{
|
|||
|
GlobalMutexRequestExternal();
|
|||
|
if (RpcAllocTlsIndex == 0xFFFFFFFF)
|
|||
|
{
|
|||
|
RpcAllocTlsIndex = TlsAlloc();
|
|||
|
if (RpcAllocTlsIndex == 0xFFFFFFFF)
|
|||
|
{
|
|||
|
GlobalMutexClearExternal();
|
|||
|
RpcRaiseException(RPC_S_OUT_OF_MEMORY);
|
|||
|
}
|
|||
|
}
|
|||
|
GlobalMutexClearExternal();
|
|||
|
}
|
|||
|
|
|||
|
return( (PALLOCATION_CONTEXT) TlsGetValue(RpcAllocTlsIndex));
|
|||
|
}
|
|||
|
|
|||
|
void
|
|||
|
SetAllocContext (
|
|||
|
PALLOCATION_CONTEXT AllocContext
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
AllocContext - Supplies a new allocation context pointer for this thread.
|
|||
|
Use GetAllocContext to retrieve the allocation context pointer for
|
|||
|
a thread.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
if ( ! TlsSetValue(RpcAllocTlsIndex, AllocContext) )
|
|||
|
RpcRaiseException( GetLastError() );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// We can't rely on a call like that in Win32 as some threads hang for ever.
|
|||
|
// The runtime doesn't call us when a thread goes away and into recycling.
|
|||
|
//
|
|||
|
//void
|
|||
|
//NdrRpcDeleteAllocationContext()
|
|||
|
//{
|
|||
|
//}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
// =======================================================================
|
|||
|
// Private entry points for stubs
|
|||
|
// =======================================================================
|
|||
|
//
|
|||
|
|
|||
|
void RPC_ENTRY
|
|||
|
NdrRpcSsEnableAllocate(
|
|||
|
PMIDL_STUB_MESSAGE pMessage )
|
|||
|
{
|
|||
|
NdrpEnableAllocate( TRUE );
|
|||
|
|
|||
|
pMessage->pfnAllocate = RpcSsAllocate;
|
|||
|
pMessage->pfnFree = RpcSsFree;
|
|||
|
}
|
|||
|
|
|||
|
void RPC_ENTRY
|
|||
|
NdrRpcSsDisableAllocate(
|
|||
|
PMIDL_STUB_MESSAGE pMessage )
|
|||
|
{
|
|||
|
NdrpDisableAllocate( TRUE );
|
|||
|
|
|||
|
pMessage->pfnAllocate = NdrRpcSsDefaultAllocate;
|
|||
|
pMessage->pfnFree = NdrRpcSsDefaultFree;
|
|||
|
}
|
|||
|
|
|||
|
void RPC_ENTRY
|
|||
|
NdrRpcSmSetClientToOsf(
|
|||
|
PMIDL_STUB_MESSAGE pMessage )
|
|||
|
{
|
|||
|
pMessage->pfnAllocate = NdrRpcSmClientAllocate;
|
|||
|
pMessage->pfnFree = NdrRpcSmClientFree;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void * RPC_ENTRY
|
|||
|
NdrRpcSsDefaultAllocate (
|
|||
|
IN size_t Size
|
|||
|
)
|
|||
|
{
|
|||
|
return I_RpcAllocate( Size );
|
|||
|
}
|
|||
|
|
|||
|
void RPC_ENTRY
|
|||
|
NdrRpcSsDefaultFree (
|
|||
|
IN void * NodeToFree
|
|||
|
)
|
|||
|
{
|
|||
|
I_RpcFree( NodeToFree );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void * RPC_ENTRY
|
|||
|
NdrRpcSmClientAllocate (
|
|||
|
IN size_t Size
|
|||
|
)
|
|||
|
/*++
|
|||
|
This is the client stub private entry point that checks if a memory
|
|||
|
manager has been enabled. If not, a default or a user's private
|
|||
|
allocator is called.
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
RPC_CLIENT_ALLOC * ClientAlloc;
|
|||
|
PALLOCATION_CONTEXT AllocationContext = GetAllocContext();
|
|||
|
|
|||
|
if ( AllocationContext == 0 )
|
|||
|
{
|
|||
|
return( DefaultAllocate( Size ));
|
|||
|
}
|
|||
|
|
|||
|
// User's ClientAlloc may encapsulate a RpcSsAllocate call.
|
|||
|
|
|||
|
EnterCriticalSection( &(AllocationContext->CriticalSection) );
|
|||
|
|
|||
|
ClientAlloc = AllocationContext->ClientAlloc;
|
|||
|
|
|||
|
LeaveCriticalSection( &(AllocationContext->CriticalSection) );
|
|||
|
|
|||
|
return (*ClientAlloc)( Size );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void RPC_ENTRY
|
|||
|
NdrRpcSmClientFree (
|
|||
|
IN void * NodeToFree
|
|||
|
)
|
|||
|
{
|
|||
|
RPC_CLIENT_FREE * ClientFree;
|
|||
|
PALLOCATION_CONTEXT AllocationContext = GetAllocContext();
|
|||
|
|
|||
|
if ( AllocationContext == 0 )
|
|||
|
{
|
|||
|
DefaultFree( NodeToFree );
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
EnterCriticalSection( &(AllocationContext->CriticalSection) );
|
|||
|
|
|||
|
ClientFree = AllocationContext->ClientFree;
|
|||
|
|
|||
|
LeaveCriticalSection( &(AllocationContext->CriticalSection) );
|
|||
|
|
|||
|
(* ClientFree)( NodeToFree );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
// =======================================================================
|
|||
|
// Private entry point for test
|
|||
|
// =======================================================================
|
|||
|
|
|||
|
|
|||
|
#if defined( DEBUGRPC )
|
|||
|
|
|||
|
void * RPC_ENTRY
|
|||
|
RpcSsGetInfo(
|
|||
|
void )
|
|||
|
{
|
|||
|
return( GetAllocContext() );
|
|||
|
}
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|