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__
|