From c5b8b3aeae8f29aadb080869463bda3aaab32e59 Mon Sep 17 00:00:00 2001 From: Ulrich Weigand Date: Sat, 22 May 1999 16:28:47 +0000 Subject: [PATCH] Improved syslevel handling, store currently held syslevels in thread database, WIN_CritSection converted to syslevel. --- if1632/kernel.spec | 10 +-- include/syslevel.h | 17 +++-- include/thread.h | 3 +- scheduler/syslevel.c | 162 +++++++++++++++++++++++++++++-------------- windows/win.c | 49 +++++-------- 5 files changed, 146 insertions(+), 95 deletions(-) diff --git a/if1632/kernel.spec b/if1632/kernel.spec index 7d8e9690b0c..a4e62a4aeda 100644 --- a/if1632/kernel.spec +++ b/if1632/kernel.spec @@ -340,11 +340,11 @@ file krnl386.exe 432 stub FileTimeToLocalFileTime 434 pascal16 UnicodeToAnsi(ptr ptr word) UnicodeToAnsi16 435 stub GetTaskFlags -436 stub _ConfirmSysLevel -437 stub _CheckNotSysLevel -438 stub _CreateSysLevel -439 stub _EnterSysLevel -440 stub _LeaveSysLevel +436 pascal16 _ConfirmSysLevel(ptr) _ConfirmSysLevel +437 pascal16 _CheckNotSysLevel(ptr) _CheckNotSysLevel +438 pascal16 _CreateSysLevel(ptr long) _CreateSysLevel +439 pascal16 _EnterSysLevel(ptr) _EnterSysLevel +440 pascal16 _LeaveSysLevel(ptr) _LeaveSysLevel 441 pascal CreateThread16(ptr long segptr segptr long ptr) THUNK_CreateThread16 442 pascal VWin32_EventCreate() VWin32_EventCreate 443 pascal VWin32_EventDestroy(long) VWin32_EventDestroy diff --git a/include/syslevel.h b/include/syslevel.h index e0fa1d7d5a6..faeb3ec5306 100644 --- a/include/syslevel.h +++ b/include/syslevel.h @@ -10,6 +10,12 @@ #include "windef.h" #include "winbase.h" +typedef struct tagSYSLEVEL +{ + CRITICAL_SECTION crst; + INT level; +} SYSLEVEL; + extern WORD SYSLEVEL_Win16CurrentTeb; extern WORD SYSLEVEL_EmergencyTeb; @@ -18,14 +24,17 @@ VOID WINAPI SYSLEVEL_EnterWin16Lock(VOID); VOID WINAPI SYSLEVEL_LeaveWin16Lock(VOID); VOID SYSLEVEL_ReleaseWin16Lock(VOID); VOID SYSLEVEL_RestoreWin16Lock(VOID); +VOID SYSLEVEL_CheckNotLevel( INT level ); -VOID WINAPI GetpWin16Lock(CRITICAL_SECTION **lock); +VOID WINAPI GetpWin16Lock(SYSLEVEL **lock); SEGPTR WINAPI GetpWin16Lock16(void); - -VOID WINAPI _EnterSysLevel(CRITICAL_SECTION *lock); -VOID WINAPI _LeaveSysLevel(CRITICAL_SECTION *lock); DWORD WINAPI _ConfirmWin16Lock(void); +VOID WINAPI _CreateSysLevel(SYSLEVEL *lock, INT level); +VOID WINAPI _EnterSysLevel(SYSLEVEL *lock); +VOID WINAPI _LeaveSysLevel(SYSLEVEL *lock); +DWORD WINAPI _ConfirmSysLevel(SYSLEVEL *lock); + VOID WINAPI ReleaseThunkLock(DWORD *mutex_count); VOID WINAPI RestoreThunkLock(DWORD mutex_count); diff --git a/include/thread.h b/include/thread.h index 9cd30a88636..66d5e50d715 100644 --- a/include/thread.h +++ b/include/thread.h @@ -9,6 +9,7 @@ #include "config.h" #include "winbase.h" +#include "syslevel.h" #include "selectors.h" /* for SET_FS */ struct _PDB; @@ -78,7 +79,7 @@ typedef struct _THDB void *entry_arg; /* 1c4 Entry point arg (was: unknown) */ DWORD unknown5[4]; /* 1c8 Unknown */ DWORD sys_count[4]; /* 1d8 Syslevel mutex entry counters */ - CRITICAL_SECTION *sys_mutex[4];/* 1e8 Syslevel mutex pointers */ + SYSLEVEL *sys_mutex[4]; /* 1e8 Syslevel mutex pointers */ DWORD unknown6[2]; /* 1f8 Unknown */ /* The following are Wine-specific fields */ int socket; /* Socket for server communication */ diff --git a/scheduler/syslevel.c b/scheduler/syslevel.c index 321e40fc4ba..5626461f282 100644 --- a/scheduler/syslevel.c +++ b/scheduler/syslevel.c @@ -5,6 +5,8 @@ */ #include +#include +#include #include "syslevel.h" #include "heap.h" #include "stackframe.h" @@ -12,7 +14,7 @@ DEFAULT_DEBUG_CHANNEL(win32) -static CRITICAL_SECTION Win16Mutex; +static SYSLEVEL Win16Mutex; static SEGPTR segpWin16Mutex; /* Global variable to save current TEB while in 16-bit code */ @@ -27,19 +29,18 @@ WORD SYSLEVEL_EmergencyTeb = 0; */ void SYSLEVEL_Init(void) { - CRITICAL_SECTION **w16Mutex = SEGPTR_ALLOC(sizeof(CRITICAL_SECTION *)); + SYSLEVEL **w16Mutex = SEGPTR_ALLOC(sizeof(SYSLEVEL *)); *w16Mutex = &Win16Mutex; segpWin16Mutex = SEGPTR_GET(w16Mutex); - InitializeCriticalSection(&Win16Mutex); - MakeCriticalSectionGlobal(&Win16Mutex); + _CreateSysLevel( &Win16Mutex, 1 ); } /************************************************************************ * GetpWin16Lock32 (KERNEL32.93) */ -VOID WINAPI GetpWin16Lock(CRITICAL_SECTION **lock) +VOID WINAPI GetpWin16Lock(SYSLEVEL **lock) { *lock = &Win16Mutex; } @@ -53,44 +54,114 @@ SEGPTR WINAPI GetpWin16Lock16(void) } /************************************************************************ - * _EnterSysLevel (KERNEL32.97) + * _CreateSysLevel (KERNEL.438) */ -VOID WINAPI _EnterSysLevel(CRITICAL_SECTION *lock) +VOID WINAPI _CreateSysLevel(SYSLEVEL *lock, INT level) { - EnterCriticalSection(lock); + InitializeCriticalSection( &lock->crst ); + MakeCriticalSectionGlobal( &lock->crst ); + lock->level = level; + + TRACE( win32, "(%p, %d): handle is %d\n", + lock, level, lock->crst.LockSemaphore ); +} + +/************************************************************************ + * _EnterSysLevel (KERNEL32.97) (KERNEL.439) + */ +VOID WINAPI _EnterSysLevel(SYSLEVEL *lock) +{ + THDB *thdb = THREAD_Current(); + int i; + + TRACE( win32, "(%p, level %d): thread %p (fs %04x, pid %d) count before %ld\n", + lock, lock->level, thdb->server_tid, thdb->teb_sel, getpid(), + thdb->sys_count[lock->level] ); + + for ( i = 3; i > lock->level; i-- ) + if ( thdb->sys_count[i] > 0 ) + { + ERR( win32, "(%p, level %d): Holding %p, level %d. Expect deadlock!\n", + lock, lock->level, thdb->sys_mutex[i], i ); + } + + EnterCriticalSection( &lock->crst ); + + thdb->sys_count[lock->level]++; + thdb->sys_mutex[lock->level] = lock; + + TRACE( win32, "(%p, level %d): thread %p (fs %04x, pid %d) count after %ld\n", + lock, lock->level, thdb->server_tid, thdb->teb_sel, getpid(), + thdb->sys_count[lock->level] ); if (lock == &Win16Mutex) GET_FS( SYSLEVEL_Win16CurrentTeb ); } /************************************************************************ - * _LeaveSysLevel (KERNEL32.98) + * _LeaveSysLevel (KERNEL32.98) (KERNEL.440) */ -VOID WINAPI _LeaveSysLevel(CRITICAL_SECTION *lock) +VOID WINAPI _LeaveSysLevel(SYSLEVEL *lock) { - LeaveCriticalSection(lock); + THDB *thdb = THREAD_Current(); + + TRACE( win32, "(%p, level %d): thread %p (fs %04x, pid %d) count before %ld\n", + lock, lock->level, thdb->server_tid, thdb->teb_sel, getpid(), + thdb->sys_count[lock->level] ); + + if ( thdb->sys_count[lock->level] <= 0 || thdb->sys_mutex[lock->level] != lock ) + { + ERR( win32, "(%p, level %d): Invalid state: count %ld mutex %p.\n", + lock, lock->level, thdb->sys_count[lock->level], + thdb->sys_mutex[lock->level] ); + } + else + { + if ( --thdb->sys_count[lock->level] == 0 ) + thdb->sys_mutex[lock->level] = NULL; + } + + LeaveCriticalSection( &lock->crst ); + + TRACE( win32, "(%p, level %d): thread %p (fs %04x, pid %d) count after %ld\n", + lock, lock->level, thdb->server_tid, thdb->teb_sel, getpid(), + thdb->sys_count[lock->level] ); } /************************************************************************ * (KERNEL32.86) */ -VOID WINAPI _KERNEL32_86(CRITICAL_SECTION *lock) +VOID WINAPI _KERNEL32_86(SYSLEVEL *lock) { _LeaveSysLevel(lock); } +/************************************************************************ + * _ConfirmSysLevel (KERNEL32.95) (KERNEL.436) + */ +DWORD WINAPI _ConfirmSysLevel(SYSLEVEL *lock) +{ + if ( lock && lock->crst.OwningThread == GetCurrentThreadId() ) + return lock->crst.RecursionCount; + else + return 0L; +} + +/************************************************************************ + * _CheckNotSysLevel (KERNEL32.94) (KERNEL.437) + */ +VOID WINAPI _CheckNotSysLevel(SYSLEVEL *lock) +{ + FIXME(win32, "(%p)\n", lock); +} + + /************************************************************************ * SYSLEVEL_EnterWin16Lock [KERNEL.480] */ VOID WINAPI SYSLEVEL_EnterWin16Lock(VOID) { - TRACE(win32, "thread %04x (pid %d) about to enter\n", - THREAD_Current()->teb_sel, getpid()); - _EnterSysLevel(&Win16Mutex); - - TRACE(win32, "thread %04x (pid %d) entered, count is %ld\n", - THREAD_Current()->teb_sel, getpid(), Win16Mutex.RecursionCount); } /************************************************************************ @@ -98,37 +169,14 @@ VOID WINAPI SYSLEVEL_EnterWin16Lock(VOID) */ VOID WINAPI SYSLEVEL_LeaveWin16Lock(VOID) { - TRACE(win32, "thread %04x (pid %d) about to leave, count is %ld\n", - THREAD_Current()->teb_sel, getpid(), Win16Mutex.RecursionCount); - _LeaveSysLevel(&Win16Mutex); } - -/************************************************************************ - * _CheckNotSysLevel (KERNEL32.94) - */ -VOID WINAPI _CheckNotSysLevel(CRITICAL_SECTION *lock) -{ - FIXME(win32, "()\n"); -} - -/************************************************************************ - * _ConfirmSysLevel (KERNEL32.95) - */ -VOID WINAPI _ConfirmSysLevel(CRITICAL_SECTION *lock) -{ - FIXME(win32, "()\n"); -} - /************************************************************************ * _ConfirmWin16Lock (KERNEL32.96) */ DWORD WINAPI _ConfirmWin16Lock(void) { - if ( Win16Mutex.OwningThread == GetCurrentThreadId() ) - return Win16Mutex.RecursionCount; - else - return 0L; + return _ConfirmSysLevel(&Win16Mutex); } /************************************************************************ @@ -136,7 +184,7 @@ DWORD WINAPI _ConfirmWin16Lock(void) */ VOID WINAPI ReleaseThunkLock(DWORD *mutex_count) { - DWORD count = Win16Mutex.RecursionCount; + DWORD count = _ConfirmSysLevel(&Win16Mutex); *mutex_count = count; while (count-- > 0) @@ -159,9 +207,6 @@ VOID SYSLEVEL_ReleaseWin16Lock(VOID) { DWORD count; - TRACE(win32, "thread %04x (pid %d) about to release, count is %ld\n", - THREAD_Current()->teb_sel, getpid(), Win16Mutex.RecursionCount); - ReleaseThunkLock(&count); if (count > 0xffff) @@ -180,12 +225,25 @@ VOID SYSLEVEL_RestoreWin16Lock(VOID) if (!count) ERR(win32, "Win16Mutex recursion count is zero!\n"); - TRACE(win32, "thread %04x (pid %d) about to restore (count %ld)\n", - THREAD_Current()->teb_sel, getpid(), count); - RestoreThunkLock(count); - - TRACE(win32, "thread %04x (pid %d) restored lock, count is %ld\n", - THREAD_Current()->teb_sel, getpid(), Win16Mutex.RecursionCount); +} + +/************************************************************************ + * SYSLEVEL_CheckNotLevel + */ +VOID SYSLEVEL_CheckNotLevel( INT level ) +{ + THDB *thdb = THREAD_Current(); + INT i; + + for ( i = 3; i >= level; i-- ) + if ( thdb->sys_count[i] > 0 ) + { + ERR( win32, "(%d): Holding lock of level %d!\n", + level, i ); + + kill( getpid(), SIGHUP ); + break; + } } diff --git a/windows/win.c b/windows/win.c index 1fa126edfc7..9f6235d91a8 100644 --- a/windows/win.c +++ b/windows/win.c @@ -33,6 +33,7 @@ #include "mdi.h" #include "local.h" #include "desktop.h" +#include "syslevel.h" DECLARE_DEBUG_CHANNEL(msg) DECLARE_DEBUG_CHANNEL(win) @@ -50,7 +51,7 @@ static WORD wDragWidth = 4; static WORD wDragHeight= 3; /* thread safeness */ -static CRITICAL_SECTION WIN_CritSection; +static SYSLEVEL WIN_SysLevel; /*********************************************************************** * WIN_Init @@ -58,8 +59,7 @@ static CRITICAL_SECTION WIN_CritSection; void WIN_Init( void ) { /* Initialisation of the critical section for thread safeness */ - InitializeCriticalSection(&WIN_CritSection); - MakeCriticalSectionGlobal(&WIN_CritSection); + _CreateSysLevel( &WIN_SysLevel, 2 ); } /*********************************************************************** @@ -67,9 +67,9 @@ void WIN_Init( void ) * * Locks access to all WND structures for thread safeness */ -void WIN_LockWnds() +void WIN_LockWnds( void ) { - EnterCriticalSection(&WIN_CritSection); + _EnterSysLevel( &WIN_SysLevel ); } /*********************************************************************** @@ -77,34 +77,24 @@ void WIN_LockWnds() * * Unlocks access to all WND structures */ -void WIN_UnlockWnds() +void WIN_UnlockWnds( void ) { - LeaveCriticalSection(&WIN_CritSection); + _LeaveSysLevel( &WIN_SysLevel ); } + /*********************************************************************** * WIN_SuspendWndsLock * * Suspend the lock on WND structures. * Returns the number of locks suspended */ -int WIN_SuspendWndsLock() +int WIN_SuspendWndsLock( void ) { - int isuspendedLocks = 0; + int isuspendedLocks = _ConfirmSysLevel( &WIN_SysLevel ); + int count = isuspendedLocks; - /* make sure that the lock is not suspended by different thread than - the owning thread */ - if(WIN_CritSection.OwningThread != GetCurrentThreadId()) - { - return 0; - } - /* set the value of isuspendedlock to the actual recursion count - of the critical section */ - isuspendedLocks = WIN_CritSection.RecursionCount; - /* set the recursion count of the critical section to 1 - so the owning thread will be able to leave it */ - while (WIN_CritSection.RecursionCount > 1) WIN_UnlockWnds(); - /* leave critical section*/ - WIN_UnlockWnds(); + while ( count-- > 0 ) + _LeaveSysLevel( &WIN_SysLevel ); return isuspendedLocks; } @@ -114,17 +104,10 @@ int WIN_SuspendWndsLock() * * Restore the suspended locks on WND structures */ -void WIN_RestoreWndsLock(int ipreviousLocks) +void WIN_RestoreWndsLock( int ipreviousLocks ) { - if(!ipreviousLocks) - { - return; - } - /* restore the lock */ - WIN_LockWnds(); - /* set the recursion count of the critical section to the - value of suspended locks (given by WIN_SuspendWndsLock())*/ - while (WIN_CritSection.RecursionCount < ipreviousLocks) WIN_LockWnds(); + while ( ipreviousLocks-- > 0 ) + _EnterSysLevel( &WIN_SysLevel ); } /***********************************************************************