///////////////////////////////////////////////////////////////////////////////
// Name:        wx/unix/private/wakeuppipe.h
// Purpose:     Helper class allowing to wake up the main thread.
// Author:      Vadim Zeitlin
// Created:     2013-06-09 (extracted from src/unix/evtloopunix.cpp)
// Copyright:   (c) 2013 Vadim Zeitlin <vadim@wxwidgets.org>
// Licence:     wxWindows licence
///////////////////////////////////////////////////////////////////////////////

#ifndef _WX_UNIX_PRIVATE_WAKEUPPIPE_H_
#define _WX_UNIX_PRIVATE_WAKEUPPIPE_H_

#include "wx/unix/pipe.h"
#include "wx/evtloopsrc.h"

// ----------------------------------------------------------------------------
// wxWakeUpPipe: allows to wake up the event loop by writing to it
// ----------------------------------------------------------------------------

// This class is not MT-safe, see wxWakeUpPipeMT below for a wake up pipe
// usable from other threads.

class wxWakeUpPipe : public wxEventLoopSourceHandler
{
public:
    // Create and initialize the pipe.
    //
    // It's the callers responsibility to add the read end of this pipe,
    // returned by GetReadFd(), to the code blocking on input.
    wxWakeUpPipe();

    // Wake up the blocking operation involving this pipe.
    //
    // It simply writes to the write end of the pipe.
    //
    // As indicated by its name, this method does no locking and so can be
    // called only from the main thread.
    void WakeUpNoLock();

    // Same as WakeUp() but without locking.

    // Return the read end of the pipe.
    int GetReadFd() { return m_pipe[wxPipe::Read]; }


    // Implement wxEventLoopSourceHandler pure virtual methods
    virtual void OnReadWaiting() override;
    virtual void OnWriteWaiting() override { }
    virtual void OnExceptionWaiting() override { }

private:
    wxPipe m_pipe;

    // This flag is set to true after writing to the pipe and reset to false
    // after reading from it in the main thread. Having it allows us to avoid
    // overflowing the pipe with too many writes if the main thread can't keep
    // up with reading from it.
    bool m_pipeIsEmpty;
};

// ----------------------------------------------------------------------------
// wxWakeUpPipeMT: thread-safe version of wxWakeUpPipe
// ----------------------------------------------------------------------------

// This class can be used from multiple threads, i.e. its WakeUp() can be
// called concurrently.

class wxWakeUpPipeMT : public wxWakeUpPipe
{
#if wxUSE_THREADS
public:
    wxWakeUpPipeMT() = default;

    // Thread-safe wrapper around WakeUpNoLock(): can be called from another
    // thread to wake up the main one.
    void WakeUp()
    {
        wxCriticalSectionLocker lock(m_pipeLock);

        WakeUpNoLock();
    }

    virtual void OnReadWaiting() override
    {
        wxCriticalSectionLocker lock(m_pipeLock);

        wxWakeUpPipe::OnReadWaiting();
    }

private:
    // Protects access to m_pipeIsEmpty.
    wxCriticalSection m_pipeLock;

#endif // wxUSE_THREADS
};

#endif // _WX_UNIX_PRIVATE_WAKEUPPIPE_H_
