731 lines
14 KiB
C++
731 lines
14 KiB
C++
//+-------------------------------------------------------------------------
|
||
//
|
||
// 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__
|