Thread: Signals on Win32 (was RE: [HACKERS] [PATCHES] fork/exec patch)
Zeugswetter Andreas wrote: > How about the typical answer on Windows ? Create an invisible Window > with an Event Handler and pass it a windows message ? The issue at hand is not how the signal is sent, but the behavior taken once it arrives. Using messages bypasses the thread problem but requires PeekMessage() to be put in various places to check if there is a signal waiting to be acted on, which is really any easier then SleepEx(0), although, it does bypass the threading issues. The other main issue with messages is that processes other than the postmaster can issue them to a backend, which has some security implications. Also, there is a series of rather nasty exploits based on WM_TIMER which have only been fixed in recent versions of windows. Merlin
Re: Signals on Win32 (was RE: [HACKERS] [PATCHES] fork/exec patch)
From
"Zeugswetter Andreas SB SD"
Date:
> > How about the typical answer on Windows ? Create an invisible Window > > with an Event Handler and pass it a windows message ? > > The issue at hand is not how the signal is sent, but the behavior taken > once it arrives. Using messages bypasses the thread problem but > requires PeekMessage() to be put in various places to check if there is > a signal waiting to be acted on, which is really any easier then > SleepEx(0), although, it does bypass the threading issues. I think that is not correct. hWnd = CreateWindow ("STATIC", "", WS_POPUP, 0, 0, 0, 0,NULL,NULL,NULL,NULL); ShowWindow (hWnd, SW_HIDE); wpOrigProc = (WNDPROC) SetWindowLong(hWnd, GWL_WNDPROC, (LONG) pg_WinProc); LRESULT APIENTRY pg_WinProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { MSG rMsg; rMsg.message = uMsg; rMsg.wParam = wParam; rMsg.lParam = lParam; // printf ("got message %d\n", rMsg.message); switch (rMsg.message) { case PG_SIGNAL_KILL: ...... } Andreas
Zeugswetter Andreas wrote: > > The issue at hand is not how the signal is sent, but the behavior taken > > once it arrives. Using messages bypasses the thread problem but > > requires PeekMessage() to be put in various places to check if there is > > a signal waiting to be acted on, which is really any easier then > > SleepEx(0), although, it does bypass the threading issues. > > I think that is not correct. > > hWnd = CreateWindow ("STATIC", "", WS_POPUP, 0, 0, 0, [...] The question is: is the event procedure running in the main thread or a separate worker thread. If it is in the main thread the signal event will not fire until the thread sleeps or explicitly checks for waiting signal messages via PeekMessage(). This also means working the callback into the main backend loop. If it is in a separate worker thread, of course the signal event will fire immediately but execution of the main thread is not suspended, unlike unix signals which suspend execution of the program. This could lead to very subtle and difficult to understand behavior unless every signal routine can be 100% certified to run parallel to the main execution line. There are a couple of different ways to suspend a thread from another thread (without true synchronization), each with inherent problems. Therefore, a message handler differs from normal thread synchronization in the following ways: 1. The message pump does not necessarily have to be in a separate thread, resulting in threadless operation. 2. The message contains both the notification and the signal itself, removing the need to used shared memory to hold the message (as in your example). 3. The message is not very secure. They can come from other processes than the postmaster. 4. When run as a service, the freedom to broadcast and receive messages is restricted. This restriction can be lifted, but this will be an unpopular decision with win32 admins. Do a search on 'service interact desktop'. The main reason it does not differ from a worker thread based signal handler using synchronization objects is does get you out have having to poll the worker thread from the main thread periodically to see if a signal has fired. This, of course is the major sticking point unless signal handlers can be certified to be thread safe; not just structural thread safety, but a more general 'do the same thing regardless if the main thread has been suspended or not'. Merlin
>> > How about the typical answer on Windows ? Create an >invisible Window >> > with an Event Handler and pass it a windows message ? >> >> The issue at hand is not how the signal is sent, but the >behavior taken >> once it arrives. Using messages bypasses the thread problem but >> requires PeekMessage() to be put in various places to check >if there is >> a signal waiting to be acted on, which is really any easier then >> SleepEx(0), although, it does bypass the threading issues. > >I think that is not correct. > > hWnd = CreateWindow ("STATIC", "", WS_POPUP, 0, 0, >0, 0,NULL,NULL,NULL,NULL); > ShowWindow (hWnd, SW_HIDE); > wpOrigProc = (WNDPROC) SetWindowLong(hWnd, >GWL_WNDPROC, (LONG) pg_WinProc); > >LRESULT APIENTRY pg_WinProc( > HWND hwnd, > UINT uMsg, > WPARAM wParam, > LPARAM lParam) >{ > MSG rMsg; > > rMsg.message = uMsg; > rMsg.wParam = wParam; > rMsg.lParam = lParam; > > // printf ("got message %d\n", rMsg.message); > switch (rMsg.message) > { > case PG_SIGNAL_KILL: > ...... >} I'm quite sure he is correct. The documentation on MSDN clearly states: [1] "An application must remove and process messages posted to the message queues of its threads. A single-threaded application usually uses a message loop in its WinMain function to remove and send messages to the appropriate window procedures for processing. Applications with multiple threads can include a message loop in each thread that creates a window." That message loops generally looks like: while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0) { if (bRet == -1) { // handle the error and possibly exit } else { TranslateMessage(&msg); DispatchMessage(&msg); } } This has to be running on the thread that owns the window. Which in this case would be the main thread of the backend, meaning it buys us nothing. A typical "proof" of this: The "hanging GUI" application. This is an application that's doing other things than working it's message loop. In that case, it can't even redraw the screen, because it can't see the messages. The other option would be a threaded application that lock itself out, but most of the applications that experience that problem is not threaded. Indeed, MS recommends you create a background thread for longer work for just this reason - to have the main thread run the message loop. This is slighly worked around in XP to make programs appear live even when they're not, see [1]. //Magnus [1]: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/w inui/windowsuserinterface/windowing/messagesandmessagequeues/aboutmessag esandmessagequeues.asp