- use intrinsic interlocked functions

- add a function to get a full stackbacktrace including usermode

svn path=/trunk/; revision=32149
This commit is contained in:
Timo Kreuzer 2008-02-06 05:09:26 +00:00
parent c759455e9e
commit 90a6601c3e

View file

@ -32,6 +32,7 @@ VOID NTAPI KeRosDumpStackFrames(PULONG, ULONG);
#ifdef GDI_DEBUG #ifdef GDI_DEBUG
BOOLEAN STDCALL KiRosPrintAddress(PVOID Address); BOOLEAN STDCALL KiRosPrintAddress(PVOID Address);
NTSYSAPI ULONG NTAPI RtlWalkFrameChain(OUT PVOID *Callers, IN ULONG Count, IN ULONG Flags);
#endif #endif
#define GDI_ENTRY_TO_INDEX(ht, e) \ #define GDI_ENTRY_TO_INDEX(ht, e) \
@ -170,7 +171,7 @@ GDIOBJ_iAllocHandleTable(OUT PSECTION_OBJECT *SectionObject)
} }
ShortDelay.QuadPart = -5000LL; /* FIXME - 0.5 ms? */ ShortDelay.QuadPart = -5000LL; /* FIXME - 0.5 ms? */
HandleTable->FirstFree = 0; HandleTable->FirstFree = 0;
HandleTable->FirstUnused = RESERVE_ENTRIES_COUNT; HandleTable->FirstUnused = RESERVE_ENTRIES_COUNT;
@ -200,8 +201,8 @@ GetObjectSize(ULONG TypeIndex)
static int leak_reported = 0; static int leak_reported = 0;
#define GDI_STACK_LEVELS 12 #define GDI_STACK_LEVELS 12
static ULONG GDIHandleAllocator[GDI_HANDLE_COUNT][GDI_STACK_LEVELS]; static ULONG GDIHandleAllocator[GDI_HANDLE_COUNT][GDI_STACK_LEVELS+1];
static ULONG GDIHandleLocker[GDI_HANDLE_COUNT][GDI_STACK_LEVELS]; static ULONG GDIHandleLocker[GDI_HANDLE_COUNT][GDI_STACK_LEVELS+1];
struct DbgOpenGDIHandle struct DbgOpenGDIHandle
{ {
ULONG idx; ULONG idx;
@ -287,6 +288,23 @@ done:
if ( i < n && h[i].count == 1 ) if ( i < n && h[i].count == 1 )
DbgPrint ( "(list terminated - the remaining entries have 1 allocation only)\n" ); DbgPrint ( "(list terminated - the remaining entries have 1 allocation only)\n" );
} }
ULONG
CaptureStackBackTace(PVOID* pFrames, ULONG nFramesToCapture)
{
ULONG nFrameCount;
memset(pFrames, 0x00, (nFramesToCapture + 1) * sizeof(PVOID));
nFrameCount = RtlCaptureStackBackTrace(1, nFramesToCapture, pFrames, NULL);
if (nFrameCount < nFramesToCapture)
{
nFrameCount += RtlWalkFrameChain(pFrames + nFrameCount, nFramesToCapture - nFrameCount, 1);
}
return nFrameCount;
}
#endif /* GDI_DEBUG */ #endif /* GDI_DEBUG */
@ -334,7 +352,7 @@ InterlockedPopFreeEntry(PGDI_HANDLE_TABLE HandleTable)
idxNextFree = (ULONG)pFreeEntry->KernelData; idxNextFree = (ULONG)pFreeEntry->KernelData;
idxPrev = (ULONG)_InterlockedCompareExchange((LONG*)&HandleTable->FirstFree, idxNextFree, idxFirstFree); idxPrev = (ULONG)_InterlockedCompareExchange((LONG*)&HandleTable->FirstFree, idxNextFree, idxFirstFree);
} }
else else
{ {
idxFirstFree = HandleTable->FirstUnused; idxFirstFree = HandleTable->FirstUnused;
idxNextFree = idxFirstFree + 1; idxNextFree = idxFirstFree + 1;
@ -470,7 +488,7 @@ GDIOBJ_AllocObj(PGDI_HANDLE_TABLE HandleTable, ULONG ObjectType)
Entry = &HandleTable->Entries[Index]; Entry = &HandleTable->Entries[Index];
LockHandle: LockHandle:
PrevProcId = InterlockedCompareExchangePointer(&Entry->ProcessId, LockedProcessId, 0); PrevProcId = _InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId, LockedProcessId, 0);
if(PrevProcId == NULL) if(PrevProcId == NULL)
{ {
HGDIOBJ Handle; HGDIOBJ Handle;
@ -485,16 +503,15 @@ LockHandle:
Entry->Type = TypeInfo; Entry->Type = TypeInfo;
/* unlock the entry */ /* unlock the entry */
(void)InterlockedExchangePointer(&Entry->ProcessId, CurrentProcessId); (void)_InterlockedExchangePointer((PVOID*)&Entry->ProcessId, CurrentProcessId);
#ifdef GDI_DEBUG #ifdef GDI_DEBUG
memset ( GDIHandleAllocator[Index], 0x00, GDI_STACK_LEVELS * sizeof(ULONG) ); CaptureStackBackTace((PVOID*)GDIHandleAllocator[Index], GDI_STACK_LEVELS);
RtlCaptureStackBackTrace(1, GDI_STACK_LEVELS, (PVOID*)GDIHandleAllocator[Index], NULL);
#endif /* GDI_DEBUG */ #endif /* GDI_DEBUG */
if(W32Process != NULL) if(W32Process != NULL)
{ {
InterlockedIncrement(&W32Process->GDIObjects); _InterlockedIncrement(&W32Process->GDIObjects);
} }
Handle = (HGDIOBJ)((Index & 0xFFFF) | (TypeInfo << GDI_ENTRY_UPPER_SHIFT)); Handle = (HGDIOBJ)((Index & 0xFFFF) | (TypeInfo << GDI_ENTRY_UPPER_SHIFT));
@ -586,8 +603,12 @@ GDIOBJ_FreeObj(PGDI_HANDLE_TABLE HandleTable, HGDIOBJ hObj, DWORD ExpectedType)
HandleType != ExpectedType) || HandleType != ExpectedType) ||
HandleType == 0 ) HandleType == 0 )
{ {
DPRINT1("Attempted to free object 0x%x of wrong type (Handle: 0x%x, expected: 0x%x)\n", DPRINT1("Attempted to free object 0x%x of wrong type (Handle: 0x%x, expected: 0x%x)\n",
hObj, HandleType, ExpectedType); hObj, HandleType, ExpectedType);
#ifdef GDI_DEBUG
DPRINT1("-> called from:\n");
KeRosDumpStackFrames(NULL, 20);
#endif
return FALSE; return FALSE;
} }
@ -596,7 +617,7 @@ GDIOBJ_FreeObj(PGDI_HANDLE_TABLE HandleTable, HGDIOBJ hObj, DWORD ExpectedType)
LockHandle: LockHandle:
/* lock the object, we must not delete global objects, so don't exchange the locking /* lock the object, we must not delete global objects, so don't exchange the locking
process ID to zero when attempting to lock a global object... */ process ID to zero when attempting to lock a global object... */
PrevProcId = InterlockedCompareExchangePointer(&Entry->ProcessId, LockedProcessId, ProcessId); PrevProcId = _InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId, LockedProcessId, ProcessId);
if(PrevProcId == ProcessId) if(PrevProcId == ProcessId)
{ {
if( (Entry->KernelData != NULL) && if( (Entry->KernelData != NULL) &&
@ -616,14 +637,14 @@ LockHandle:
Entry->Type = (Entry->Type + GDI_ENTRY_REUSE_INC) & ~GDI_ENTRY_BASETYPE_MASK; Entry->Type = (Entry->Type + GDI_ENTRY_REUSE_INC) & ~GDI_ENTRY_BASETYPE_MASK;
/* unlock the handle slot */ /* unlock the handle slot */
(void)InterlockedExchangePointer(&Entry->ProcessId, NULL); (void)_InterlockedExchangePointer((PVOID*)&Entry->ProcessId, NULL);
/* push this entry to the free list */ /* push this entry to the free list */
InterlockedPushFreeEntry(HandleTable, GDI_ENTRY_TO_INDEX(HandleTable, Entry)); InterlockedPushFreeEntry(HandleTable, GDI_ENTRY_TO_INDEX(HandleTable, Entry));
if(W32Process != NULL) if(W32Process != NULL)
{ {
InterlockedDecrement(&W32Process->GDIObjects); _InterlockedDecrement(&W32Process->GDIObjects);
} }
/* call the cleanup routine. */ /* call the cleanup routine. */
@ -662,7 +683,7 @@ LockHandle:
else else
{ {
LockErrorDebugOutput(hObj, Entry, "GDIOBJ_FreeObj"); LockErrorDebugOutput(hObj, Entry, "GDIOBJ_FreeObj");
(void)InterlockedExchangePointer(&Entry->ProcessId, PrevProcId); (void)_InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
} }
} }
else if(PrevProcId == LockedProcessId) else if(PrevProcId == LockedProcessId)
@ -883,7 +904,7 @@ GDIOBJ_LockObj (PGDI_HANDLE_TABLE HandleTable, HGDIOBJ hObj, DWORD ExpectedType)
{ {
/* Lock the handle table entry. */ /* Lock the handle table entry. */
LockedProcessId = (HANDLE)((ULONG_PTR)HandleProcessId | 0x1); LockedProcessId = (HANDLE)((ULONG_PTR)HandleProcessId | 0x1);
PrevProcId = InterlockedCompareExchangePointer(&Entry->ProcessId, PrevProcId = _InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId,
LockedProcessId, LockedProcessId,
HandleProcessId); HandleProcessId);
@ -905,20 +926,19 @@ GDIOBJ_LockObj (PGDI_HANDLE_TABLE HandleTable, HGDIOBJ hObj, DWORD ExpectedType)
GdiHdr->LockingThread = Thread; GdiHdr->LockingThread = Thread;
GdiHdr->Locks = 1; GdiHdr->Locks = 1;
#ifdef GDI_DEBUG #ifdef GDI_DEBUG
memset(GDIHandleLocker[GDI_HANDLE_GET_INDEX(hObj)], 0x00, GDI_STACK_LEVELS * sizeof(ULONG)); CaptureStackBackTace((PVOID*)GDIHandleLocker[GDI_HANDLE_GET_INDEX(hObj)], GDI_STACK_LEVELS);
RtlCaptureStackBackTrace(1, GDI_STACK_LEVELS, (PVOID*)GDIHandleLocker[GDI_HANDLE_GET_INDEX(hObj)], NULL);
#endif #endif
Object = Entry->KernelData; Object = Entry->KernelData;
} }
else else
{ {
InterlockedIncrement((PLONG)&GdiHdr->Locks); _InterlockedIncrement((PLONG)&GdiHdr->Locks);
if (GdiHdr->LockingThread != Thread) if (GdiHdr->LockingThread != Thread)
{ {
InterlockedDecrement((PLONG)&GdiHdr->Locks); _InterlockedDecrement((PLONG)&GdiHdr->Locks);
/* Unlock the handle table entry. */ /* Unlock the handle table entry. */
(void)InterlockedExchangePointer(&Entry->ProcessId, PrevProcId); (void)_InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
DelayExecution(); DelayExecution();
continue; continue;
@ -941,7 +961,7 @@ GDIOBJ_LockObj (PGDI_HANDLE_TABLE HandleTable, HGDIOBJ hObj, DWORD ExpectedType)
} }
/* Unlock the handle table entry. */ /* Unlock the handle table entry. */
(void)InterlockedExchangePointer(&Entry->ProcessId, PrevProcId); (void)_InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
break; break;
} }
@ -1028,7 +1048,7 @@ GDIOBJ_ShareLockObj (PGDI_HANDLE_TABLE HandleTable, HGDIOBJ hObj, DWORD Expected
{ {
/* Lock the handle table entry. */ /* Lock the handle table entry. */
LockedProcessId = (HANDLE)((ULONG_PTR)HandleProcessId | 0x1); LockedProcessId = (HANDLE)((ULONG_PTR)HandleProcessId | 0x1);
PrevProcId = InterlockedCompareExchangePointer(&Entry->ProcessId, PrevProcId = _InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId,
LockedProcessId, LockedProcessId,
HandleProcessId); HandleProcessId);
@ -1045,13 +1065,13 @@ GDIOBJ_ShareLockObj (PGDI_HANDLE_TABLE HandleTable, HGDIOBJ hObj, DWORD Expected
PGDIOBJHDR GdiHdr = GDIBdyToHdr(Entry->KernelData); PGDIOBJHDR GdiHdr = GDIBdyToHdr(Entry->KernelData);
#ifdef GDI_DEBUG #ifdef GDI_DEBUG
if (InterlockedIncrement((PLONG)&GdiHdr->Locks) == 1) if (_InterlockedIncrement((PLONG)&GdiHdr->Locks) == 1)
{ {
memset(GDIHandleLocker[HandleIndex], 0x00, GDI_STACK_LEVELS * sizeof(ULONG)); memset(GDIHandleLocker[HandleIndex], 0x00, GDI_STACK_LEVELS * sizeof(ULONG));
RtlCaptureStackBackTrace(1, GDI_STACK_LEVELS, (PVOID*)GDIHandleLocker[HandleIndex], NULL); RtlCaptureStackBackTrace(1, GDI_STACK_LEVELS, (PVOID*)GDIHandleLocker[HandleIndex], NULL);
} }
#else #else
InterlockedIncrement((PLONG)&GdiHdr->Locks); _InterlockedIncrement((PLONG)&GdiHdr->Locks);
#endif #endif
Object = Entry->KernelData; Object = Entry->KernelData;
} }
@ -1070,7 +1090,7 @@ GDIOBJ_ShareLockObj (PGDI_HANDLE_TABLE HandleTable, HGDIOBJ hObj, DWORD Expected
} }
/* Unlock the handle table entry. */ /* Unlock the handle table entry. */
(void)InterlockedExchangePointer(&Entry->ProcessId, PrevProcId); (void)_InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
break; break;
} }
@ -1102,13 +1122,13 @@ GDIOBJ_UnlockObjByPtr(PGDI_HANDLE_TABLE HandleTable, PGDIOBJ Object)
{ {
PGDIOBJHDR GdiHdr = GDIBdyToHdr(Object); PGDIOBJHDR GdiHdr = GDIBdyToHdr(Object);
#ifdef GDI_DEBUG #ifdef GDI_DEBUG
if (InterlockedDecrement((PLONG)&GdiHdr->Locks) == 0) if (_InterlockedDecrement((PLONG)&GdiHdr->Locks) == 0)
{ {
memset(GDIHandleLocker[GDI_HANDLE_GET_INDEX(Object)], 0x00, GDI_STACK_LEVELS * sizeof(ULONG)); memset(GDIHandleLocker[GDI_HANDLE_GET_INDEX(Object)], 0x00, GDI_STACK_LEVELS * sizeof(ULONG));
RtlCaptureStackBackTrace(1, GDI_STACK_LEVELS, (PVOID*)GDIHandleLocker[GDI_HANDLE_GET_INDEX(Object)], NULL); RtlCaptureStackBackTrace(1, GDI_STACK_LEVELS, (PVOID*)GDIHandleLocker[GDI_HANDLE_GET_INDEX(Object)], NULL);
} }
#else #else
if (InterlockedDecrement((PLONG)&GdiHdr->Locks) < 0) if (_InterlockedDecrement((PLONG)&GdiHdr->Locks) < 0)
DPRINT1("Trying to unlock non-existant object\n"); DPRINT1("Trying to unlock non-existant object\n");
#endif #endif
} }
@ -1168,7 +1188,7 @@ GDIOBJ_ConvertToStockObj(PGDI_HANDLE_TABLE HandleTable, HGDIOBJ *phObj)
LockHandle: LockHandle:
/* lock the object, we must not convert stock objects, so don't check!!! */ /* lock the object, we must not convert stock objects, so don't check!!! */
PrevProcId = InterlockedCompareExchangePointer(&Entry->ProcessId, LockedProcessId, ProcessId); PrevProcId = _InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId, LockedProcessId, ProcessId);
if(PrevProcId == ProcessId) if(PrevProcId == ProcessId)
{ {
LONG NewType, PrevType, OldType; LONG NewType, PrevType, OldType;
@ -1188,7 +1208,7 @@ LockHandle:
NewType = OldType | GDI_ENTRY_STOCK_MASK; NewType = OldType | GDI_ENTRY_STOCK_MASK;
/* Try to exchange the type field - but only if the old (previous type) matches! */ /* Try to exchange the type field - but only if the old (previous type) matches! */
PrevType = InterlockedCompareExchange(&Entry->Type, NewType, OldType); PrevType = _InterlockedCompareExchange(&Entry->Type, NewType, OldType);
if(PrevType == OldType && Entry->KernelData != NULL) if(PrevType == OldType && Entry->KernelData != NULL)
{ {
PETHREAD PrevThread; PETHREAD PrevThread;
@ -1217,14 +1237,14 @@ LockHandle:
W32Process = (PW32PROCESS)OldProcess->Win32Process; W32Process = (PW32PROCESS)OldProcess->Win32Process;
if(W32Process != NULL) if(W32Process != NULL)
{ {
InterlockedDecrement(&W32Process->GDIObjects); _InterlockedDecrement(&W32Process->GDIObjects);
} }
ObDereferenceObject(OldProcess); ObDereferenceObject(OldProcess);
} }
} }
/* remove the process id lock and make it global */ /* remove the process id lock and make it global */
(void)InterlockedExchangePointer(&Entry->ProcessId, GDI_GLOBAL_PROCESS); (void)_InterlockedExchangePointer((PVOID*)&Entry->ProcessId, GDI_GLOBAL_PROCESS);
hObj = (HGDIOBJ)((ULONG)(hObj) | GDI_HANDLE_STOCK_MASK); hObj = (HGDIOBJ)((ULONG)(hObj) | GDI_HANDLE_STOCK_MASK);
*phObj = hObj; *phObj = hObj;
@ -1246,7 +1266,7 @@ LockHandle:
/* WTF?! The object is already locked by a different thread! /* WTF?! The object is already locked by a different thread!
Release the lock, wait a bit and try again! Release the lock, wait a bit and try again!
FIXME - we should give up after some time unless we want to wait forever! */ FIXME - we should give up after some time unless we want to wait forever! */
(void)InterlockedExchangePointer(&Entry->ProcessId, PrevProcId); (void)_InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
DelayExecution(); DelayExecution();
goto LockHandle; goto LockHandle;
@ -1304,7 +1324,7 @@ GDIOBJ_SetOwnership(PGDI_HANDLE_TABLE HandleTable, HGDIOBJ ObjectHandle, PEPROCE
LockHandle: LockHandle:
/* lock the object, we must not convert stock objects, so don't check!!! */ /* lock the object, we must not convert stock objects, so don't check!!! */
PrevProcId = InterlockedCompareExchangePointer(&Entry->ProcessId, ProcessId, LockedProcessId); PrevProcId = _InterlockedCompareExchangePointer((PVOID*)&Entry->ProcessId, ProcessId, LockedProcessId);
if(PrevProcId == ProcessId) if(PrevProcId == ProcessId)
{ {
PETHREAD PrevThread; PETHREAD PrevThread;
@ -1330,7 +1350,7 @@ LockHandle:
W32Process = (PW32PROCESS)OldProcess->Win32Process; W32Process = (PW32PROCESS)OldProcess->Win32Process;
if(W32Process != NULL) if(W32Process != NULL)
{ {
InterlockedDecrement(&W32Process->GDIObjects); _InterlockedDecrement(&W32Process->GDIObjects);
} }
ObDereferenceObject(OldProcess); ObDereferenceObject(OldProcess);
} }
@ -1344,14 +1364,14 @@ LockHandle:
W32Process = (PW32PROCESS)NewOwner->Win32Process; W32Process = (PW32PROCESS)NewOwner->Win32Process;
if(W32Process != NULL) if(W32Process != NULL)
{ {
InterlockedIncrement(&W32Process->GDIObjects); _InterlockedIncrement(&W32Process->GDIObjects);
} }
} }
else else
ProcessId = 0; ProcessId = 0;
/* remove the process id lock and change it to the new process id */ /* remove the process id lock and change it to the new process id */
(void)InterlockedExchangePointer(&Entry->ProcessId, ProcessId); (void)_InterlockedExchangePointer((PVOID*)&Entry->ProcessId, ProcessId);
/* we're done! */ /* we're done! */
return; return;
@ -1370,7 +1390,7 @@ LockHandle:
being deleted in the meantime (because we don't have aquired a reference being deleted in the meantime (because we don't have aquired a reference
at this point). at this point).
FIXME - we should give up after some time unless we want to wait forever! */ FIXME - we should give up after some time unless we want to wait forever! */
(void)InterlockedExchangePointer(&Entry->ProcessId, PrevProcId); (void)_InterlockedExchangePointer((PVOID*)&Entry->ProcessId, PrevProcId);
DelayExecution(); DelayExecution();
goto LockHandle; goto LockHandle;
@ -1437,7 +1457,7 @@ GDIOBJ_CopyOwnership(PGDI_HANDLE_TABLE HandleTable, HGDIOBJ CopyFrom, HGDIOBJ Co
LockHandleFrom: LockHandleFrom:
/* lock the object, we must not convert stock objects, so don't check!!! */ /* lock the object, we must not convert stock objects, so don't check!!! */
FromPrevProcId = InterlockedCompareExchangePointer(&FromEntry->ProcessId, FromProcessId, FromLockedProcessId); FromPrevProcId = _InterlockedCompareExchangePointer((PVOID*)&FromEntry->ProcessId, FromProcessId, FromLockedProcessId);
if(FromPrevProcId == FromProcessId) if(FromPrevProcId == FromProcessId)
{ {
PETHREAD PrevThread; PETHREAD PrevThread;
@ -1470,7 +1490,7 @@ LockHandleFrom:
GDIOBJ_SetOwnership(HandleTable, CopyTo, NULL); GDIOBJ_SetOwnership(HandleTable, CopyTo, NULL);
} }
(void)InterlockedExchangePointer(&FromEntry->ProcessId, FromPrevProcId); (void)_InterlockedExchangePointer((PVOID*)&FromEntry->ProcessId, FromPrevProcId);
} }
else else
{ {
@ -1486,7 +1506,7 @@ LockHandleFrom:
being deleted in the meantime (because we don't have aquired a reference being deleted in the meantime (because we don't have aquired a reference
at this point). at this point).
FIXME - we should give up after some time unless we want to wait forever! */ FIXME - we should give up after some time unless we want to wait forever! */
(void)InterlockedExchangePointer(&FromEntry->ProcessId, FromPrevProcId); (void)_InterlockedExchangePointer((PVOID*)&FromEntry->ProcessId, FromPrevProcId);
DelayExecution(); DelayExecution();
goto LockHandleFrom; goto LockHandleFrom;