diff --git a/include/wx/unix/app.h b/include/wx/unix/app.h index ca3f3744c0..812783bcef 100644 --- a/include/wx/unix/app.h +++ b/include/wx/unix/app.h @@ -11,10 +11,17 @@ //Ensure that sigset_t is being defined #include +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; }; diff --git a/src/unix/appunix.cpp b/src/unix/appunix.cpp index 5c59dec71c..f0733e2ada 100644 --- a/src/unix/appunix.cpp +++ b/src/unix/appunix.cpp @@ -20,6 +20,10 @@ #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 #include @@ -29,6 +33,58 @@ #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 + 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;