From 6619f5a71ac55a7ab5d0110bf59d5fd01e86f379 Mon Sep 17 00:00:00 2001 From: Peter Ganten Date: Sat, 1 Jan 2000 22:38:20 +0000 Subject: [PATCH] Implemented WaitForInputIdle. --- if1632/thunk.c | 1 + include/callback.h | 1 + include/process.h | 3 ++ loader/module.c | 6 +++- scheduler/process.c | 15 +++++++-- windows/message.c | 13 ++++--- windows/queue.c | 82 ++++++++++++++++++++++++++++++++++++++++----- windows/user.c | 40 +++++++++++++++++++--- 8 files changed, 142 insertions(+), 19 deletions(-) diff --git a/if1632/thunk.c b/if1632/thunk.c index 5501e7d12d6..51cfa2a3dbe 100644 --- a/if1632/thunk.c +++ b/if1632/thunk.c @@ -375,6 +375,7 @@ void THUNK_InitCallout(void) GETADDR( DispatchMessageW, "DispatchMessageW" ); GETADDR( DispatchMessageA, "DispatchMessageA" ); GETADDR( RedrawWindow, "RedrawWindow" ); + GETADDR( WaitForInputIdle, "WaitForInputIdle" ); #undef GETADDR } diff --git a/include/callback.h b/include/callback.h index 44a49a08014..7bf4343386e 100644 --- a/include/callback.h +++ b/include/callback.h @@ -103,6 +103,7 @@ typedef struct HQUEUE16 WINAPI (*InitThreadInput16)( WORD unknown, WORD flags ); void WINAPI (*UserYield16)( void ); WORD WINAPI (*DestroyIcon32)( HGLOBAL16 handle, UINT16 flags ); + DWORD WINAPI (*WaitForInputIdle)( HANDLE hProcess, DWORD dwTimeOut ); } CALLOUT_TABLE; diff --git a/include/process.h b/include/process.h index b1d923687ba..54665c1ca8b 100644 --- a/include/process.h +++ b/include/process.h @@ -96,6 +96,8 @@ typedef struct _PDB struct _PDB *next; /* List reference - list of PDB's */ WORD winver; /* Windows version figured out by VERSION_GetVersion */ struct _SERVICETABLE *service_table; /* Service table for service thread */ + HANDLE idle_event; /* event to signal, when the process is idle */ + HANDLE16 main_queue; /* main message queue of the process */ } PDB; /* Process flags */ @@ -146,6 +148,7 @@ typedef struct _PDB extern DWORD WINAPI GetProcessDword( DWORD dwProcessID, INT offset ); void WINAPI SetProcessDword( DWORD dwProcessID, INT offset, DWORD value ); +extern DWORD WINAPI MapProcessHandle( HANDLE handle ); /* scheduler/environ.c */ extern BOOL ENV_InheritEnvironment( PDB *pdb, LPCSTR env ); diff --git a/loader/module.c b/loader/module.c index 89916f95299..5813d3b468c 100644 --- a/loader/module.c +++ b/loader/module.c @@ -834,6 +834,10 @@ HINSTANCE WINAPI LoadModule( LPCSTR name, LPVOID paramBlock ) return 11; } + /* Give 30 seconds to the app to come up */ + if ( Callout.WaitForInputIdle ( info.hProcess, 30000 ) == 0xFFFFFFFF ) + WARN("WaitForInputIdle failed: Error %ld\n", GetLastError() ); + /* Get 16-bit hInstance/hTask from process */ pdb = PROCESS_IdToPDB( info.dwProcessId ); tdb = pdb? (TDB *)GlobalLock16( pdb->task ) : NULL; @@ -1289,7 +1293,7 @@ HMODULE WINAPI GetModuleHandleW(LPCWSTR module) /*********************************************************************** - * GetModuleFileName32A (KERNEL32.235) + * GetModuleFileNameA (KERNEL32.235) */ DWORD WINAPI GetModuleFileNameA( HMODULE hModule, /* [in] module handle (32bit) */ diff --git a/scheduler/process.c b/scheduler/process.c index b30e24d1408..d9ff8fd1291 100644 --- a/scheduler/process.c +++ b/scheduler/process.c @@ -313,6 +313,7 @@ static PDB *PROCESS_CreatePDB( PDB *parent, BOOL inherit ) pdb->heap = pdb->system_heap; /* will be changed later on */ pdb->next = PROCESS_First; pdb->winver = 0xffff; /* to be determined */ + pdb->main_queue = INVALID_HANDLE_VALUE16; PROCESS_First = pdb; return pdb; } @@ -338,6 +339,7 @@ BOOL PROCESS_Init(void) initial_pdb.priority = 8; /* Normal */ initial_pdb.flags = PDB32_WIN16_PROC; initial_pdb.winver = 0xffff; /* to be determined */ + initial_pdb.main_queue = INVALID_HANDLE_VALUE16; /* Initialize virtual memory management */ if (!VIRTUAL_Init()) return FALSE; @@ -352,6 +354,14 @@ BOOL PROCESS_Init(void) if (!(SystemHeap = HeapCreate( HEAP_GROWABLE, 0x10000, 0 ))) return FALSE; initial_pdb.system_heap = initial_pdb.heap = SystemHeap; + /* Create the idle event for the initial process + FIXME 1: Shouldn't we call UserSignalProc for the initial process too? + FIXME 2: It seems to me that the initial pdb becomes never freed, so I don't now + where to release the idle event for the initial process. + */ + initial_pdb.idle_event = CreateEventA ( NULL, TRUE, FALSE, NULL ); + initial_pdb.idle_event = ConvertToGlobalHandle ( initial_pdb.idle_event ); + /* Initialize signal handling */ if (!SIGNAL_Init()) return FALSE; @@ -485,8 +495,9 @@ void PROCESS_Start(void) if ( Options.debug && TASK_AddTaskEntryBreakpoint ) TASK_AddTaskEntryBreakpoint( pdb->task ); - /* Now call the entry point */ - PROCESS_CallUserSignalProc( USIG_PROCESS_RUNNING, 0, 0 ); + /* Call UserSignalProc ( USIG_PROCESS_RUNNING ... ) only for non-GUI win32 apps */ + if ( type != PROC_WIN16 && (pdb->flags & PDB32_CONSOLE_PROC)) + PROCESS_CallUserSignalProc( USIG_PROCESS_RUNNING, 0, 0 ); switch ( type ) { diff --git a/windows/message.c b/windows/message.c index b21f809e659..91dc327fffc 100644 --- a/windows/message.c +++ b/windows/message.c @@ -1933,6 +1933,7 @@ DWORD WINAPI MsgWaitForMultipleObjects( DWORD nCount, HANDLE *pHandles, DWORD i; HANDLE handles[MAXIMUM_WAIT_OBJECTS]; DWORD ret; + PDB * pdb = PROCESS_Current(); HQUEUE16 hQueue = GetFastQueue16(); MESSAGEQUEUE *msgQueue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue ); @@ -1968,6 +1969,7 @@ DWORD WINAPI MsgWaitForMultipleObjects( DWORD nCount, HANDLE *pHandles, /* * Check the handles in the list. */ + SetEvent ( pdb->idle_event ); ret = WaitForMultipleObjects(nCount, pHandles, fWaitAll, 5L); /* @@ -2000,9 +2002,13 @@ DWORD WINAPI MsgWaitForMultipleObjects( DWORD nCount, HANDLE *pHandles, /* Add the thread event to the handle list */ for (i = 0; i < nCount; i++) handles[i] = pHandles[i]; - handles[nCount] = msgQueue->hEvent; + handles[nCount] = msgQueue->hEvent; + + if ( pdb->main_queue == INVALID_HANDLE_VALUE16 ) pdb->main_queue = hQueue; + if ( pdb->main_queue == hQueue ) SetEvent ( pdb->idle_event ); + ret = WaitForMultipleObjects( nCount+1, handles, fWaitAll, dwMilliseconds ); + if ( pdb->main_queue == hQueue ) ResetEvent ( pdb->idle_event ); - ret = WaitForMultipleObjects( nCount+1, handles, fWaitAll, dwMilliseconds ); } QUEUE_Unlock( msgQueue ); @@ -2488,8 +2494,7 @@ DWORD WINAPI GetTickCount(void) { struct timeval t; gettimeofday( &t, NULL ); - /* make extremely compatible: granularity is 25 msec */ - return ((t.tv_sec * 1000) + (t.tv_usec / 25000) * 25) - MSG_WineStartTicks; + return ((t.tv_sec * 1000) + (t.tv_usec / 1000)) - MSG_WineStartTicks; } diff --git a/windows/queue.c b/windows/queue.c index cc710320064..3b88261e8b2 100644 --- a/windows/queue.c +++ b/windows/queue.c @@ -5,6 +5,7 @@ #include #include +#include #include "wine/winbase16.h" #include "wine/winuser16.h" #include "miscemu.h" @@ -18,7 +19,6 @@ #include "heap.h" #include "thread.h" #include "process.h" -#include #include "debugtools.h" #include "spy.h" @@ -467,7 +467,7 @@ static HQUEUE16 QUEUE_CreateMsgQueue( BOOL16 bCreatePerQData ) if (msgQueue->hEvent == 0) { - WARN_(msg)("CreateEvent32A is not able to create an event object"); + WARN_(msg)("CreateEventA is not able to create an event object"); return 0; } msgQueue->hEvent = ConvertToGlobalHandle( msgQueue->hEvent ); @@ -672,14 +672,19 @@ int QUEUE_WaitBits( WORD bits, DWORD timeout ) { MESSAGEQUEUE *queue; DWORD curTime = 0; + HQUEUE16 hQueue; + PDB * pdb; TRACE_(msg)("q %04x waiting for %04x\n", GetFastQueue16(), bits); if ( THREAD_IsWin16( NtCurrentTeb() ) && (timeout != INFINITE) ) curTime = GetTickCount(); - if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() ))) return 0; + hQueue = GetFastQueue16(); + if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( hQueue ))) return 0; + pdb = PROCESS_Current(); + for (;;) { if (queue->changeBits & bits) @@ -716,7 +721,24 @@ int QUEUE_WaitBits( WORD bits, DWORD timeout ) TRACE_(msg)("bHasWin16Lock=TRUE\n"); ReleaseThunkLock( &dwlc ); } + + + if ( pdb->main_queue == INVALID_HANDLE_VALUE16 ) + { + pdb->main_queue = hQueue; + } + if ( pdb->main_queue == hQueue ) + { + SetEvent ( pdb->idle_event ); + } + WaitForSingleObject( queue->hEvent, timeout ); + + if ( pdb->main_queue == hQueue ) + { + ResetEvent ( pdb->idle_event ); + } + if ( bHasWin16Lock ) { RestoreThunkLock( dwlc ); @@ -724,6 +746,8 @@ int QUEUE_WaitBits( WORD bits, DWORD timeout ) } else { + SetEvent ( pdb->idle_event ); + if ( timeout == INFINITE ) WaitEvent16( 0 ); /* win 16 thread, use WaitEvent */ else @@ -1395,7 +1419,7 @@ BOOL16 WINAPI SetMessageQueue16( INT16 size ) /*********************************************************************** - * SetMessageQueue32 (USER32.494) + * SetMessageQueue (USER32.494) */ BOOL WINAPI SetMessageQueue( INT size ) { @@ -1409,7 +1433,7 @@ BOOL WINAPI SetMessageQueue( INT size ) } /*********************************************************************** - * InitThreadInput (USER.409) + * InitThreadInput16 (USER.409) */ HQUEUE16 WINAPI InitThreadInput16( WORD unknown, WORD flags ) { @@ -1430,7 +1454,7 @@ HQUEUE16 WINAPI InitThreadInput16( WORD unknown, WORD flags ) { WARN_(msg)("failed!\n"); return FALSE; - } + } /* Link new queue into list */ queuePtr = (MESSAGEQUEUE *)QUEUE_Lock( hQueue ); @@ -1496,12 +1520,54 @@ BOOL16 WINAPI GetInputState16(void) */ DWORD WINAPI WaitForInputIdle (HANDLE hProcess, DWORD dwTimeOut) { - FIXME_(msg)("(hProcess=%d, dwTimeOut=%ld): stub\n", hProcess, dwTimeOut); + PDB * pdb; + DWORD cur_time, ret, pid = MapProcessHandle ( hProcess ); + /* Check whether the calling process is a command line application */ + if (!THREAD_IsWin16(NtCurrentTeb() ) && + (PROCESS_Current()->flags & PDB32_CONSOLE_PROC)) + { + TRACE_(msg)("not a win32 GUI application!\n" ); + return 0; + } + + pdb = PROCESS_IdToPDB( pid ); + + /* check whether we are waiting for a win32 process or the win16 subsystem */ + if ( pdb->flags & PDB32_WIN16_PROC ) { + if ( THREAD_IsWin16(NtCurrentTeb()) ) return 0; + } + else { /* target is win32 */ + if ( pdb->flags & PDB32_CONSOLE_PROC ) return 0; + if ( GetFastQueue16() == pdb->main_queue ) return 0; + } + + cur_time = GetTickCount(); + + TRACE_(msg)("waiting for %x\n", pdb->idle_event ); + while ( dwTimeOut > GetTickCount() - cur_time || dwTimeOut == INFINITE ) { + + ret = MsgWaitForMultipleObjects ( 1, &pdb->idle_event, FALSE, dwTimeOut, QS_SENDMESSAGE ); + if ( ret == ( WAIT_OBJECT_0 + 1 )) { + MESSAGEQUEUE * queue; + if (!(queue = (MESSAGEQUEUE *)QUEUE_Lock( GetFastQueue16() ))) return 0xFFFFFFFF; + QUEUE_ReceiveMessage ( queue ); + QUEUE_Unlock ( queue ); + continue; + } + if ( ret == WAIT_TIMEOUT || ret == 0xFFFFFFFF ) { + TRACE_(msg)("timeout or error\n"); + return ret; + } + else { + TRACE_(msg)("finished\n"); + return 0; + } + + } return WAIT_TIMEOUT; } - /*********************************************************************** * GetInputState32 (USER32.244) */ diff --git a/windows/user.c b/windows/user.c index fc3e1b6c6ab..68f380efea9 100644 --- a/windows/user.c +++ b/windows/user.c @@ -207,7 +207,9 @@ void WINAPI FinalUserInit16( void ) WORD WINAPI UserSignalProc( UINT uCode, DWORD dwThreadOrProcessID, DWORD dwFlags, HMODULE16 hModule ) { + static HANDLE win16_idle_event; HINSTANCE16 hInst; + PDB * pdb; /* FIXME: Proper reaction to most signals still missing. */ @@ -234,18 +236,48 @@ WORD WINAPI UserSignalProc( UINT uCode, DWORD dwThreadOrProcessID, break; case USIG_PROCESS_CREATE: + pdb = PROCESS_IdToPDB( dwThreadOrProcessID ); + + /* Create the idle event for the process. We have just one idle_event for all + win16 processes, while each win32 process has its own */ + + if ( pdb->flags & PDB32_WIN16_PROC ) + { + if (!win16_idle_event) + { + win16_idle_event = CreateEventA ( NULL, TRUE, FALSE, NULL ); + win16_idle_event = ConvertToGlobalHandle ( win16_idle_event ); + } + pdb->idle_event = win16_idle_event; + } + else { /* win32 process */ + pdb->idle_event = CreateEventA ( NULL, TRUE, FALSE, NULL ); + pdb->idle_event = ConvertToGlobalHandle ( pdb->idle_event ); + TRACE_(win)("created win32 idle event: %x\n", pdb->idle_event ); + } + break; + case USIG_PROCESS_INIT: case USIG_PROCESS_LOADED: + break; case USIG_PROCESS_RUNNING: + pdb = PROCESS_IdToPDB ( dwThreadOrProcessID ); + SetEvent ( pdb->idle_event ); break; case USIG_PROCESS_EXIT: break; - case USIG_PROCESS_DESTROY: - hInst = GetProcessDword( dwThreadOrProcessID, GPD_HINSTANCE16 ); - USER_AppExit( hInst ); - break; + case USIG_PROCESS_DESTROY: + hInst = GetProcessDword( dwThreadOrProcessID, GPD_HINSTANCE16 ); + USER_AppExit( hInst ); + + pdb = PROCESS_IdToPDB( dwThreadOrProcessID ); + if ( ! (pdb->flags & PDB32_WIN16_PROC) ) { + TRACE_(win)("destroying win32 idle event: %x\n", pdb->idle_event ); + CloseHandle ( pdb->idle_event ); + } + break; default: FIXME_(win)("(%04x, %08lx, %04lx, %04x)\n",