windows-nt/Source/XPSP1/NT/com/rpc/runtime/mtrt/threads.hxx

731 lines
14 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1990 - 1999
//
// File: threads.hxx
//
//--------------------------------------------------------------------------
/* --------------------------------------------------------------------
Microsoft OS/2 LAN Manager
Copyright(c) Microsoft Corp., 1990
-------------------------------------------------------------------- */
/* --------------------------------------------------------------------
File: threads.hxx
Description:
This file provides a system independent threads package.
History:
mikemon 05/24/90 File created.
mikemon 10/15/90 Added the PauseExecution entry point.
Kamen Moutafov (KamenM) Dec 99 - Feb 2000 - Support for cell debugging stuff
-------------------------------------------------------------------- */
#ifndef __THREADS__
#define __THREADS__
#include <interlck.hxx>
class CALL;
class LRPC_CCALL;
class SCALL;
typedef BOOL
(*THREAD_PROC) (
void * Parameter
);
typedef HANDLE THREAD_IDENTIFIER;
class THREAD
{
friend void
RpcpPurgeEEInfoFromThreadIfNecessary (
IN THREAD *ThisThread
);
private:
static const unsigned int CallDestroyedWithOutstandingLocks = 1;
static const unsigned int CallCancelled = 2;
static const unsigned int Yielded = 4;
#ifdef RPC_OLD_IO_PROTECTION
LONG ProtectCount;
#endif
public:
BOOL fAsync;
long CancelTimeout;
private:
HANDLE HandleToThread;
public:
EVENT ThreadEvent;
void * Context;
void * SecurityContext;
BCACHE_STATE BufferCache[4];
// write-on-multiple-threads section, buffered with unused (rarely used) variables
RPC_STATUS ExtendedStatus;
CellTag DebugCellTag;
DebugThreadInfo *DebugCell;
private:
THREAD_PROC SavedProcedure;
void * SavedParameter;
CALL * ActiveCall;
#ifdef RPC_OLD_IO_PROTECTION
INTERLOCKED_INTEGER ReleaseCount;
#endif
ExtendedErrorInfo *ThreadEEInfo;
void *NDRSlot;
// a cached LRPC call - essnetially the same that a LRPC_CALL constructor
// will give. This is never used in the non-server versions of the product
LRPC_CCALL *CachedLrpcCall;
CompositeFlags Flags;
void *LastSuccessfullyDestroyedContext;
// cached waiter blocks
// a pointer to the last cached waiter we have. It must
// never be equal to &CachedWaiter
SWMRWaiter *CachedWaiterPtr;
// a buffer where we can cookup a waiter using the thread event
SWMRWaiter CachedWaiter;
ExtendedErrorInfo *CachedEEInfoBlock;
ULONG ParametersOfCachedEEInfo; // how many parameters does the
// CachedEEInfoBlock has
public:
#ifdef CHECK_MUTEX_INVERSION
void * ConnectionMutexHeld;
#endif
// Construct a new thread which will execute the procedure specified, taking
// Param as the argument.
THREAD (
IN THREAD_PROC Procedure,
IN void * Parameter,
OUT RPC_STATUS * RpcStatus
);
THREAD (
OUT RPC_STATUS * RpcStatus
);
~THREAD (
);
void
StartRoutine (
) {(*SavedProcedure)(SavedParameter);}
void *
ThreadHandle (
);
friend THREAD * ThreadSelf();
friend void * RpcpGetThreadContext();
friend void RpcpSetThreadContext(void * Context);
#ifdef RPC_OLD_IO_PROTECTION
long
InqProtectCount (
);
#endif
void
CommonConstructor (
);
RPC_STATUS
SetCancelTimeout (
IN long Timeout
);
BOOL
IsSyncCall (
) {return !fAsync;}
BOOL
IsIOPending();
void
SetExtendedError (
IN RPC_STATUS Status
)
{
ExtendedStatus = Status;
}
RPC_STATUS
GetExtendedError (
)
{
return ExtendedStatus;
}
RPC_STATUS
CancelCall (
IN BOOL fTimeoutValid = FALSE,
IN long Timeout = 0
);
RPC_STATUS
RegisterForCancels (
IN CALL *Call
);
void
UnregisterForCancels (
);
void
YieldThread (
)
{
LARGE_INTEGER TimeOut;
PLARGE_INTEGER pTimeOut;
NTSTATUS Status;
if (GetYieldedFlag() == 0)
{
SetYieldedFlag();
//
// Sleep for the smallest possible time
//
TimeOut.QuadPart = Int32x32To64( 1, -1 );
pTimeOut = &TimeOut;
do
{
Status = NtDelayExecution(
(BOOLEAN)FALSE,
pTimeOut
);
} while (Status == STATUS_ALERTED);
}
}
void
ResetYield()
{
ClearYieldedFlag();
}
void
PurgeEEInfo (
void
);
inline ExtendedErrorInfo *
GetEEInfo (
void
)
{
return ThreadEEInfo;
}
inline void
SetEEInfo (
ExtendedErrorInfo *NewEEInfo
)
{
ThreadEEInfo = NewEEInfo;
}
inline void *
GetNDRSlot (
void
)
{
return NDRSlot;
}
inline void
SetNDRSlot (
void *NewNDRSlot
)
{
NDRSlot = NewNDRSlot;
}
inline LRPC_CCALL *
GetCachedLrpcCall (
void
)
{
return CachedLrpcCall;
}
inline void
SetCachedLrpcCall (
LRPC_CCALL *NewCall
)
{
CachedLrpcCall = NewCall;
}
inline void *
GetLastSuccessfullyDestroyedContext (
void
)
{
return LastSuccessfullyDestroyedContext;
}
inline void
SetLastSuccessfullyDestroyedContext (
void *NewLastSuccessfullyDestroyedContext
)
{
LastSuccessfullyDestroyedContext = NewLastSuccessfullyDestroyedContext;
}
void
GetWaiterCache (
OUT SWMRWaiter **WaiterCache,
IN SCALL *SCall,
IN SWMRWaiterType WaiterType
);
void
FreeWaiterCache (
IN OUT SWMRWaiter **WaiterCache
);
inline void
SetCachedEEInfoBlock (
IN ExtendedErrorInfo *EEInfoBlock,
IN ULONG NumberOfParamsInBlock
)
{
if (CachedEEInfoBlock == NULL)
{
CachedEEInfoBlock = EEInfoBlock;
ParametersOfCachedEEInfo = NumberOfParamsInBlock;
}
else if (NumberOfParamsInBlock > ParametersOfCachedEEInfo)
{
// we have an incoming block larger than the cache - keep
// the larger and throw away the smaller
FreeEEInfoRecordShallow(CachedEEInfoBlock);
CachedEEInfoBlock = EEInfoBlock;
ParametersOfCachedEEInfo = NumberOfParamsInBlock;
}
else
{
FreeEEInfoRecordShallow(EEInfoBlock);
}
}
inline ExtendedErrorInfo *
GetCachedEEInfoBlock (
IN ULONG NumberOfParamsInBlock
)
{
ExtendedErrorInfo *LocalEEInfo = NULL;
if (CachedEEInfoBlock && (NumberOfParamsInBlock <= ParametersOfCachedEEInfo))
{
// N.B. Here we can get gradual degradation of the cached block
// as we take out a larger block, but we return a block whose
// size we think is only the number of used parameters. For example,
// if we have in the cache block with 4 parameters, and we take
// it out, and we use it on record with 2 parameters, we will
// return the block through SetCachedEEInfoBlock as a 2-parameter
// block. This means that the next time we need 4 parameters, we
// may go to the heap, even though we have a large enough block
// in the thread cache. That's ok. The way to avoid this is to keep
// the real size of the block in the eeinfo record, which is too
// big a waste of space and code. The current method handles the
// Exchange server too busy error, which is the main consumer of
// this cache
LocalEEInfo = CachedEEInfoBlock;
CachedEEInfoBlock = NULL;
ParametersOfCachedEEInfo = 0;
}
return LocalEEInfo;
}
inline void
SetDestroyedWithOutstandingLocksFlag (
void
)
{
Flags.SetFlagUnsafe(CallDestroyedWithOutstandingLocks);
}
inline BOOL
GetDestroyedWithOutstandingLocksFlag (
void
)
{
return Flags.GetFlag(CallDestroyedWithOutstandingLocks);
}
inline void
ClearDestroyedWithOutstandingLocksFlag (
void
)
{
Flags.ClearFlagUnsafe(CallDestroyedWithOutstandingLocks);
}
inline void
SetCallCancelledFlag (
void
)
{
Flags.SetFlagUnsafe(CallCancelled);
}
inline BOOL
GetCallCancelledFlag (
void
)
{
return Flags.GetFlag(CallCancelled);
}
inline void
ClearCallCancelledFlag (
void
)
{
Flags.ClearFlagUnsafe(CallCancelled);
}
inline void
SetYieldedFlag (
void
)
{
Flags.SetFlagUnsafe(Yielded);
}
inline BOOL
GetYieldedFlag (
void
)
{
return Flags.GetFlag(Yielded);
}
inline void
ClearYieldedFlag (
void
)
{
Flags.ClearFlagUnsafe(Yielded);
}
};
inline BOOL
THREAD::IsIOPending()
{
NTSTATUS Status;
BOOL IsIoPending;
Status = NtQueryInformationThread(
HandleToThread,
ThreadIsIoPending,
&IsIoPending,
sizeof(IsIoPending),
NULL
);
return (NT_SUCCESS(Status) && IsIoPending);
}
extern THREAD_IDENTIFIER
GetThreadIdentifier (
);
extern void PauseExecution(unsigned long time);
// This class represents a dynamic link library. When it is constructed,
// the dll is loaded, and when it is destructed, the dll is unloaded.
// The only operation is obtaining the address of an entry point into
// the dll.
class DLL
{
private:
void * DllHandle;
public:
DLL (
IN RPC_CHAR * DllName,
OUT RPC_STATUS * Status
);
~DLL (
);
void *
GetEntryPoint (
IN char * Procedure
);
};
extern int
InitializeThreads (
);
extern void
UninitializeThreads (
);
extern RPC_STATUS
SetThreadStackSize (
IN unsigned long ThreadStackSize
);
extern long
ThreadGetRpcCancelTimeout(
);
extern void
ThreadSetRpcCancelTimeout(
long Timeout
);
RPC_STATUS
RegisterForCancels(
CALL * Call
);
RPC_STATUS
UnregisterForCancels(
);
RPC_STATUS
RpcpThreadCancel(
void * ThreadHandle
);
BOOL
ThreadCancelsEnabled (
);
VOID RPC_ENTRY
CancelAPCRoutine (
ULONG_PTR Timeout
);
VOID RPC_ENTRY
CancelExAPCRoutine (
ULONG_PTR Timeout
);
RPC_STATUS
RpcpGetThreadPointerFromHandle(
void * ThreadHandle,
THREAD * * pThread
);
inline THREAD *
RpcpGetThreadPointer(
)
{
return (THREAD *) NtCurrentTeb()->ReservedForNtRpc;
}
inline void
RpcpSetThreadPointer(
THREAD * Thread
)
{
NtCurrentTeb()->ReservedForNtRpc = Thread;
}
inline THREAD_IDENTIFIER
GetThreadIdentifier (
)
{
return(NtCurrentTeb()->ClientId.UniqueThread);
}
#pragma optimize ("t", on)
inline void
RpcpPurgeEEInfoFromThreadIfNecessary (
IN THREAD *ThisThread
)
{
if (ThisThread->ThreadEEInfo)
ThisThread->PurgeEEInfo();
}
#pragma optimize("", on)
inline void
RpcpPurgeEEInfo (
void
)
{
THREAD *ThisThread = RpcpGetThreadPointer();
ASSERT(ThisThread);
RpcpPurgeEEInfoFromThreadIfNecessary(ThisThread);
}
inline ExtendedErrorInfo *
RpcpGetEEInfo (
void
)
{
THREAD *ThisThread = RpcpGetThreadPointer();
ASSERT(ThisThread);
return ThisThread->GetEEInfo();
}
inline void
RpcpSetEEInfoForThread (
THREAD *ThisThread,
ExtendedErrorInfo *EEInfo
)
{
ASSERT(ThisThread->GetEEInfo() == NULL);
ThisThread->SetEEInfo(EEInfo);
}
inline void
RpcpSetEEInfo (
ExtendedErrorInfo *EEInfo
)
{
THREAD *ThisThread = RpcpGetThreadPointer();
ASSERT(ThisThread);
RpcpSetEEInfoForThread(ThisThread, EEInfo);
}
inline void
RpcpClearEEInfoForThread (
THREAD *ThisThread
)
{
ThisThread->SetEEInfo(NULL);
}
inline void
RpcpClearEEInfo (
void
)
{
THREAD *ThisThread = RpcpGetThreadPointer();
ASSERT(ThisThread);
RpcpClearEEInfoForThread(ThisThread);
}
inline RPC_STATUS
RpcpSetNDRSlot (
IN void *NewSlot
)
{
THREAD *ThisThread = ThreadSelf();
if (ThisThread == NULL)
return RPC_S_OUT_OF_MEMORY;
ThisThread->SetNDRSlot(NewSlot);
return RPC_S_OK;
}
inline void *
RpcpGetNDRSlot (
void
)
{
THREAD *ThisThread = RpcpGetThreadPointer();
ASSERT(ThisThread);
return ThisThread->GetNDRSlot();
}
THREAD *
ThreadSelfHelper (
);
#pragma optimize ("t", on)
inline THREAD *
ThreadSelf (
)
{
RPC_STATUS Status;
THREAD * Thread = RpcpGetThreadPointer();
if (Thread)
{
return Thread;
}
return(ThreadSelfHelper());
}
#pragma optimize("", on)
inline void *
RpcpGetThreadContext (
)
{
THREAD * Thread = ThreadSelf();
if (Thread == 0)
{
return(0);
}
return(Thread->Context);
}
inline void
RpcpSetThreadContextWithThread (
IN THREAD *ThisThread,
IN void * Context
)
{
ThisThread->Context = Context;
ThisThread->fAsync = FALSE;
}
inline void
RpcpSetThreadContext (
IN void * Context
)
{
THREAD *Thread = RpcpGetThreadPointer();
RpcpSetThreadContextWithThread(Thread, Context);
}
void
SetExtendedError(
IN RPC_STATUS Status
);
#endif // __THREADS__