]> git.saurik.com Git - wxWidgets.git/commitdiff
Make Unix wxAppConsole signal handling more flexible.
authorVadim Zeitlin <vadim@wxwidgets.org>
Wed, 3 Jul 2013 00:31:03 +0000 (00:31 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Wed, 3 Jul 2013 00:31:03 +0000 (00:31 +0000)
Instead of hardcoding the call to WakeUpIdle() in the signal handler itself,
just wake up the event loop when we catch a signal. This will still result in
WakeUpIdle() being called, before the next event loop iteration, but it will
also allow us to do other things on wakeup from signal as it will be done in
the upcoming wxExecute() changes to support wxEXEC_NOEVENTS in console
applications.

See #10258.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@74347 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

include/wx/unix/app.h
src/unix/appunix.cpp

index ca3f3744c00dcc0d7fd2d97c2c6b7d450baba867..812783bcef3d038d668be74c5efc5bbfd6802b19 100644 (file)
 //Ensure that sigset_t is being defined
 #include <signal.h>
 
+class wxFDIODispatcher;
+class wxFDIOHandler;
+class wxWakeUpPipe;
+
 // wxApp subclass implementing event processing for console applications
 class WXDLLIMPEXP_BASE wxAppConsole : public wxAppConsoleBase
 {
 public:
+    wxAppConsole();
+    virtual ~wxAppConsole();
+
     // override base class initialization
     virtual bool Initialize(int& argc, wxChar** argv);
 
@@ -38,6 +45,14 @@ public:
     // handlers for them
     void CheckSignal();
 
+    // Register the signal wake up pipe with the given dispatcher.
+    //
+    // This is not used anywhere yet but will be soon.
+    //
+    // The pointer to the handler used for processing events on this descriptor
+    // is returned so that it can be deleted when we no longer needed it.
+    wxFDIOHandler* RegisterSignalWakeUpPipe(wxFDIODispatcher& dispatcher);
+
 private:
     // signal handler set up by SetSignalHandler() for all signals we handle,
     // it just adds the signal to m_signalsCaught -- the real processing is
@@ -52,4 +67,8 @@ private:
     // the signal handlers
     WX_DECLARE_HASH_MAP(int, SignalHandler, wxIntegerHash, wxIntegerEqual, SignalHandlerHash);
     SignalHandlerHash m_signalHandlerHash;
+
+    // pipe used for wake up signal handling: if a signal arrives while we're
+    // blocking for input, writing to this pipe triggers a call to our CheckSignal()
+    wxWakeUpPipe *m_signalWakeUpPipe;
 };
index 5c59dec71ca6d81a702dd9f7381ed713f249cefd..f0733e2ada1e39b1e8d4a98344ced8faee268800 100644 (file)
 #endif
 
 #include "wx/evtloop.h"
+#include "wx/scopedptr.h"
+#include "wx/unix/private/wakeuppipe.h"
+#include "wx/private/fdiodispatcher.h"
+#include "wx/private/fdioeventloopsourcehandler.h"
 
 #include <signal.h>
 #include <unistd.h>
     #define SA_RESTART 0
 #endif
 
+// ----------------------------------------------------------------------------
+// Helper class calling CheckSignal() on wake up
+// ----------------------------------------------------------------------------
+
+namespace
+{
+
+class SignalsWakeUpPipe : public wxWakeUpPipe
+{
+public:
+    // Ctor automatically registers this pipe with the event loop.
+    SignalsWakeUpPipe()
+    {
+        m_source = wxEventLoopBase::AddSourceForFD
+                                    (
+                                        GetReadFd(),
+                                        this,
+                                        wxEVENT_SOURCE_INPUT
+                                    );
+    }
+
+    virtual void OnReadWaiting()
+    {
+        // The base class wxWakeUpPipe::OnReadWaiting() needs to be called in order
+        // to read the data out of the wake up pipe and clear it for next time.
+        wxWakeUpPipe::OnReadWaiting();
+
+        if ( wxTheApp )
+            wxTheApp->CheckSignal();
+    }
+
+    virtual ~SignalsWakeUpPipe()
+    {
+        delete m_source;
+    }
+
+private:
+    wxEventLoopSource* m_source;
+};
+
+} // anonymous namespace
+
+wxAppConsole::wxAppConsole()
+{
+    m_signalWakeUpPipe = NULL;
+}
+
+wxAppConsole::~wxAppConsole()
+{
+    delete m_signalWakeUpPipe;
+}
+
 // use unusual names for arg[cv] to avoid clashes with wxApp members with the
 // same names
 bool wxAppConsole::Initialize(int& argc_, wxChar** argv_)
@@ -41,14 +97,23 @@ bool wxAppConsole::Initialize(int& argc_, wxChar** argv_)
     return true;
 }
 
+// The actual signal handler. It does as little as possible (because very few
+// things are safe to do from inside a signal handler) and just ensures that
+// CheckSignal() will be called later from SignalsWakeUpPipe::OnReadWaiting().
 void wxAppConsole::HandleSignal(int signal)
 {
     wxAppConsole * const app = wxTheApp;
     if ( !app )
         return;
 
+    // Register the signal that is caught.
     sigaddset(&(app->m_signalsCaught), signal);
-    app->WakeUpIdle();
+
+    // Wake up the application for handling the signal.
+    //
+    // Notice that we must have a valid wake up pipe here as we only install
+    // our signal handlers after allocating it.
+    app->m_signalWakeUpPipe->WakeUpNoLock();
 }
 
 void wxAppConsole::CheckSignal()
@@ -66,6 +131,27 @@ void wxAppConsole::CheckSignal()
     }
 }
 
+wxFDIOHandler* wxAppConsole::RegisterSignalWakeUpPipe(wxFDIODispatcher& dispatcher)
+{
+    wxCHECK_MSG( m_signalWakeUpPipe, false, "Should be allocated" );
+
+    // we need a bridge to wxFDIODispatcher
+    //
+    // TODO: refactor the code so that only wxEventLoopSourceHandler is used
+    wxScopedPtr<wxFDIOHandler>
+        fdioHandler(new wxFDIOEventLoopSourceHandler(m_signalWakeUpPipe));
+
+    if ( !dispatcher.RegisterFD
+                     (
+                      m_signalWakeUpPipe->GetReadFd(),
+                      fdioHandler.get(),
+                      wxFDIO_INPUT
+                     ) )
+        return NULL;
+
+    return fdioHandler.release();
+}
+
 // the type of the signal handlers we use is "void(*)(int)" while the real
 // signal handlers are extern "C" and so have incompatible type and at least
 // Sun CC warns about it, so use explicit casts to suppress these warnings as
@@ -80,6 +166,13 @@ bool wxAppConsole::SetSignalHandler(int signal, SignalHandler handler)
     const bool install = (SignalHandler_t)handler != SIG_DFL &&
                          (SignalHandler_t)handler != SIG_IGN;
 
+    if ( !m_signalWakeUpPipe )
+    {
+        // Create the pipe that the signal handler will use to cause the event
+        // loop to call wxAppConsole::CheckSignal().
+        m_signalWakeUpPipe = new SignalsWakeUpPipe();
+    }
+
     struct sigaction sa;
     memset(&sa, 0, sizeof(sa));
     sa.sa_handler = (SignalHandler_t)&wxAppConsole::HandleSignal;