/* Copyright (C) 2005 to 2014 Chris Vine

The library comprised in this file or of which this file is part is
distributed by Chris Vine under the GNU Lesser General Public
License as follows:

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public License
   as published by the Free Software Foundation; either version 2.1 of
   the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License, version 2.1, for more details.

   You should have received a copy of the GNU Lesser General Public
   License, version 2.1, along with this library (see the file LGPL.TXT
   which came with this source code package in the c++-gtk-utils
   sub-directory); if not, write to the Free Software Foundation, Inc.,
   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

*/

#ifndef CGU_IO_WATCH_H
#define CGU_IO_WATCH_H

/**
 */

/**
 * @defgroup io_watch io_watch
 *
 * \#include <c++-gtk-utils/io_watch.h>
 *
 * The start_iowatch() function connects a Unix file descriptor to an
 * event loop owned by a GMainContext object (normally the main
 * program loop).  It both saves the overhead of having to construct a
 * GIOChannel object where the only thing wanted is to execute a
 * callback when there is something to be read from a pipe, fifo or
 * socket or a pipe or fifo can be written to, and it also provides
 * for automatic disconnection when an object whose function the
 * callback represents is destroyed.
 *
 * For the GIOCondition argument of start_iowatch(), G_IO_IN can be
 * bitwise-ORed with G_IO_HUP, and should be if the callback has the
 * task of cleaning up if EOF is reached (see
 * http://www.greenend.org.uk/rjk/2001/06/poll.html ), which is
 * detected by read() returning 0.  A cast will be required to do this
 * for the third argument of start_iowatch() (that is, pass
 * GIOCondition(G_IO_IN | G_IO_HUP)).  In addition, G_IO_IN and
 * G_IO_OUT can be bitwise-ORed with G_IO_ERR (and passed as
 * GIOCondition(G_IO_IN | G_IO_HUP | G_IO_ERR) or
 * GIOCondition(G_IO_OUT | G_IO_ERR)), which would be detected in the
 * callback by read() or write() returning -1.
 *
 * Two of the four overloaded start_iowatch() functions also take a
 * Callback object having a GIOCondition type and bool& type as their
 * unbound arguments (the other two overloads only have callbacks
 * taking a single bool& unbound argument).  The overloads taking a
 * Callback object with an unbound GIOCondition argument type are,
 * when the callback function is executed, passed a GIOCondition value
 * to that argument, representing the bitwise-ORed events which caused
 * the call: this enables a single watch to be provided for both
 * reading and writing (if the file descriptor has been opened for
 * reading and writing), by testing for G_IO_IN and G_IO_OUT on that
 * argument in the callback function.  It also enables, by testing for
 * G_IO_HUP and G_IO_ERR, a hang-up or error condition to be detected
 * without having to inspect the return value of read() or write()
 * (but note the test results referred to in
 * http://www.greenend.org.uk/rjk/2001/06/poll.html , which show that
 * the ending of a connection can only reliably be determined by
 * testing whether read() returns 0, or whether the iostream wrapper
 * on top of it reports end of file after attempting a read.)
 *
 * start_iowatch() is thread-safe (it may be called in any thread)
 * provided that, if glib < 2.32 is used, the glib main loop has been
 * made thread-safe by a call to g_thread_init().  glib >= 2.32 does
 * not require g_thread_init() to be called in order to be
 * thread-safe.
 *
 * start_iowatch() takes ownership of the passed Callback object.  Two
 * of the four start_iowatch() overloads take a Callback::Releaser
 * object as their third argument, which provides for automatic
 * ceasing of the watch if the target object which has the Releaser as
 * a member is destroyed.  (Note that for this to be race free, the
 * lifetime of the remote target object whose method is to be invoked
 * must be determined by the thread to whose main loop the watch has
 * been attached.  When the main loop begins invoking the execution of
 * the watch callback, the remote object must either wholly exist, in
 * which case the callback will be invoked, or have been destroyed, in
 * which case the callback will be ignored, and not be in some
 * transient half-state governed by another thread.)
 *
 * As mentioned above, the connected function encapsulated by the
 * callback passed to start_iowatch() must have a second (or only)
 * unbound bool& argument.  If that bool& argument is set by the
 * connected function to false, say because end-of-file has been
 * reached, then the watch will be ended and all resources connected
 * with it deleted without further user action being required (there
 * is no need for the connected function to set it to true if the
 * watch is to continue, as that is the default).  In addition, the
 * watch will be ended automatically and resources deleted if (i) as
 * mentioned above, the callback passed to start_iowatch() is
 * protected by a Releaser object and the target object whose method
 * is encapsulated by the callback is destroyed, or (ii)
 * g_source_remove() is called on the source id returned by
 * start_iowatch() (where the watch is attached to the default main
 * context) or g_source_destroy() is called on the GSource object
 * obtained from that id with g_main_context_find_source_by_id()
 * (where the watch has been attached to a non-default main context).
 * If the source has been removed automatically by virtue of the bool&
 * argument being set to false or by virtue of a Releaser object
 * releasing, g_source_remove() or g_source_destroy() should not
 * afterwards be called in respect of the id value returned by
 * start_iowatch() in case it has been reused by the main context
 * concerned in the meantime.
 */

#include <glib.h>
#include <c++-gtk-utils/callback.h>
#include <c++-gtk-utils/cgu_config.h>

namespace Cgu {

class Releaser;

/**
 * Starts an io watch in the glib main loop on a file descriptor, and
 * executes the callback if the condition in io_condition is met.  It
 * is thread-safe (it may be called in any thread) provided that, if
 * glib < 2.32 is used, g_thread_init() has been called.  glib >= 2.32
 * does not require g_thread_init() to be called to be thread-safe.
 * From version 2.0.24 of the library this function will not throw.
 * (Prior to that, it could throw std::bad_alloc if memory was
 * exhausted and the system threw in that case, or
 * Cgu::Thread::MutexError if initialisation of the mutex in a
 * SafeEmitterArg object failed, in which case the CallbackArg object
 * would be disposed of.)
 * @param fd The file descriptor.
 * @param cb The callback object.  Ownership is taken of this object,
 * and it will be deleted when it has been finished with
 * @param io_condition The condition to be watched for (G_IO_IN may be
 * bitwise-ored with G_IO_HUP, and G_IO_IN and G_IO_OUT may be
 * bitwise-ored with G_IO_ERR).
 * @param priority The priority to be given to the watch in the main
 * loop.  In ascending order of priorities, priorities are
 * G_PRIORITY_LOW, G_PRIORITY_DEFAULT_IDLE, G_PRIORITY_HIGH_IDLE,
 * G_PRIORITY_DEFAULT and G_PRIORITY_HIGH. The default is
 * G_PRIORITY_DEFAULT.  This determines the order in which the
 * callback will appear in the event list in the main loop, not the
 * priority which the OS will adopt
 * @param context The glib main context to which the watch is to be
 * attached (the default of NULL will cause the watch to be attached
 * to the main program loop, and this is almost always what is
 * wanted).
 * @return The glib source id of the watch.
 * @note 1. Cancellation of the thread to which the watch is attached
 * is blocked during execution of the callback.
 * @note 2. If the callback throws an exception, the exception will be
 * consumed to protect the main loop and a g_critical() warning will
 * be issued.
 * @ingroup io_watch
 */
guint start_iowatch(int fd, const Callback::CallbackArg<bool&>* cb,
		    GIOCondition io_condition, gint priority = G_PRIORITY_DEFAULT,
		    GMainContext* context = 0);

/**
 * Starts an io watch in the glib main loop on a file descriptor, and
 * executes the callback if the condition in io_condition is met.
 * This version provides for automatic watch disconnection when the
 * object whose function the callback represents is destroyed, via the
 * Releaser object.  It is thread-safe (it may be called in any
 * thread) provided that, if glib < 2.32 is used, g_thread_init() has
 * been called.  glib >= 2.32 does not require g_thread_init() to be
 * called to be thread-safe.
 * @param fd The file descriptor.
 * @param cb The callback object.  Ownership is taken of this object,
 * and it will be deleted when it has been finished with.
 * @param r A Releaser object which the protected object has as a
 * public member.
 * @param io_condition The condition to be watched for (G_IO_IN may be
 * bitwise-ored with G_IO_HUP, and G_IO_IN and G_IO_OUT may be
 * bitwise-ored with G_IO_ERR).
 * @param priority The priority to be given to the watch in the main
 * loop.  In ascending order of priorities, priorities are
 * G_PRIORITY_LOW, G_PRIORITY_DEFAULT_IDLE, G_PRIORITY_HIGH_IDLE,
 * G_PRIORITY_DEFAULT and G_PRIORITY_HIGH. The default is
 * G_PRIORITY_DEFAULT.  This determines the order in which the
 * callback will appear in the event list in the main loop, not the
 * priority which the OS will adopt
 * @param context The glib main context to which the watch is to be
 * attached (the default of NULL will cause the watch to be attached
 * to the main program loop, and this is almost always what is
 * wanted).
 * @return The glib source id of the watch.
 * @exception std::bad_alloc This function might throw std::bad_alloc
 * if memory is exhausted and the system throws in that case.  If it
 * does so, the CallbackArg object will be disposed of.
 * @exception Cgu::Thread::MutexError This function might throw
 * Cgu:Thread::MutexError if initialisation of the mutex in a
 * SafeEmitterArg object constructed by this function fails.  If it
 * does so, the CallbackArg object will be disposed of.  (It is often
 * not worth checking for this exception, as it means either memory is
 * exhausted or pthread has run out of other resources to create new
 * mutexes.)
 * @note 1. Cancellation of the thread to which the watch is attached
 * is blocked during execution of the callback.
 * @note 2. If the callback throws an exception, the exception will be
 * consumed to protect the main loop and a g_critical() warning will
 * be issued.
 * @ingroup io_watch
 */
guint start_iowatch(int fd, const Callback::CallbackArg<bool&>* cb, Releaser& r,
		    GIOCondition io_condition, gint priority = G_PRIORITY_DEFAULT,
		    GMainContext* context = 0);

/**
 * Starts an io watch in the glib main loop on a file descriptor, and
 * executes the callback if the condition in io_condition is met.
 * This version provides the GIOCondition status which caused the
 * callback to be invoked as the first unbound argument of the
 * callback object.  It is thread-safe (it may be called in any
 * thread) provided that, if glib < 2.32 is used, g_thread_init() has
 * been called.  glib >= 2.32 does not require g_thread_init() to be
 * called to be thread-safe.  From version 2.0.24 of the library this
 * function will not throw.  (Prior to that, it could throw
 * std::bad_alloc if memory was exhausted and the system threw in that
 * case, or Cgu::Thread::MutexError if initialisation of the mutex in
 * a SafeEmitterArg object failed, in which case the CallbackArg
 * object would be disposed of.)
 * @param fd The file descriptor.
 * @param cb The callback object.  Ownership is taken of this object,
 * and it will be deleted when it has been finished with.
 * @param io_condition The condition(s) to be watched for (G_IO_IN,
 * G_IO_OUT, G_IO_HUP and G_IO_ERR may all be bitwise-ored).
 * @param priority The priority to be given to the watch in the main
 * loop.  In ascending order of priorities, priorities are
 * G_PRIORITY_LOW, G_PRIORITY_DEFAULT_IDLE, G_PRIORITY_HIGH_IDLE,
 * G_PRIORITY_DEFAULT and G_PRIORITY_HIGH. The default is
 * G_PRIORITY_DEFAULT.  This determines the order in which the
 * callback will appear in the event list in the main loop, not the
 * priority which the OS will adopt
 * @param context The glib main context to which the watch is to be
 * attached (the default of NULL will cause the watch to be attached
 * to the main program loop, and this is almost always what is
 * wanted).
 * @return The glib source id of the watch.
 * @note 1. Cancellation of the thread to which the watch is attached
 * is blocked during execution of the callback.
 * @note 2. If the callback throws an exception, the exception will be
 * consumed to protect the main loop and a g_critical() warning will
 * be issued.
 * @ingroup io_watch
 * 
 * Since 2.0.0-rc2
 */
guint start_iowatch(int fd, const Callback::CallbackArg<GIOCondition, bool&>* cb,
		    GIOCondition io_condition, gint priority = G_PRIORITY_DEFAULT,
		    GMainContext* context = 0);

/**
 * Starts an io watch in the glib main loop on a file descriptor, and
 * executes the callback if the condition in io_condition is met.
 * This version provides both automatic watch disconnection when the
 * object whose function the callback represents is destroyed, via the
 * Releaser object, and provides the GIOCondition status which caused
 * the callback to be invoked as the first unbound argument of the
 * callback object.  It is thread-safe (it may be called in any
 * thread) provided that, if glib < 2.32 is used, g_thread_init() has
 * been called.  glib >= 2.32 does not require g_thread_init() to be
 * called to be thread-safe.
 * @param fd The file descriptor.
 * @param cb The callback object.  Ownership is taken of this object,
 * and it will be deleted when it has been finished with.
 * @param r A Releaser object which the protected object has as a
 * public member.
 * @param io_condition The condition(s) to be watched for (G_IO_IN,
 * G_IO_OUT, G_IO_HUP and G_IO_ERR may all be bitwise-ored).
 * @param priority The priority to be given to the watch in the main
 * loop.  In ascending order of priorities, priorities are
 * G_PRIORITY_LOW, G_PRIORITY_DEFAULT_IDLE, G_PRIORITY_HIGH_IDLE,
 * G_PRIORITY_DEFAULT and G_PRIORITY_HIGH. The default is
 * G_PRIORITY_DEFAULT.  This determines the order in which the
 * callback will appear in the event list in the main loop, not the
 * priority which the OS will adopt
 * @param context The glib main context to which the watch is to be
 * attached (the default of NULL will cause the watch to be attached
 * to the main program loop, and this is almost always what is
 * wanted).
 * @return The glib source id of the watch.
 * @exception std::bad_alloc This function might throw std::bad_alloc
 * if memory is exhausted and the system throws in that case.  If it
 * does so, the CallbackArg object will be disposed of.
 * @exception Cgu::Thread::MutexError This function might throw
 * Cgu:Thread::MutexError if initialisation of the mutex in a
 * SafeEmitterArg object constructed by this function fails.  If it
 * does so, the CallbackArg object will be disposed of.  (It is often
 * not worth checking for this exception, as it means either memory is
 * exhausted or pthread has run out of other resources to create new
 * mutexes.)
 * @note 1. Cancellation of the thread to which the watch is attached
 * is blocked during execution of the callback.
 * @note 2. If the callback throws an exception, the exception will be
 * consumed to protect the main loop and a g_critical() warning will
 * be issued.
 * @ingroup io_watch
 * 
 * Since 2.0.0-rc2
 */
guint start_iowatch(int fd, const Callback::CallbackArg<GIOCondition, bool&>* cb,
		    Releaser& r, GIOCondition io_condition, gint priority = G_PRIORITY_DEFAULT,
		    GMainContext* context = 0);

} // namespace Cgu

#endif
