[kdbus] KDBUS_ITEM_PAYLOAD_OFF items are (once again) relative to msg header
[platform/upstream/glib.git] / glib / gwakeup.c
index 60c2a9e..c0f1ba0 100644 (file)
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  *
  * Author: Ryan Lortie <desrt@desrt.ca>
  */
 
 #include "config.h"
 
+
+/* gwakeup.c is special -- GIO and some test cases include it.  As such,
+ * it cannot include other glib headers without triggering the single
+ * includes warnings.  We have to manually include its dependencies here
+ * (and at all other use sites).
+ */
+#ifdef GLIB_COMPILATION
+#include "gtypes.h"
+#include "gpoll.h"
+#else
+#include <glib.h>
+#endif
+
 #include "gwakeup.h"
 
+/*< private >
+ * SECTION:gwakeup
+ * @title: GWakeup
+ * @short_description: portable cross-thread event signal mechanism
+ *
+ * #GWakeup is a simple and portable way of signaling events between
+ * different threads in a way that integrates nicely with g_poll().
+ * GLib uses it internally for cross-thread signalling in the
+ * implementation of #GMainContext and #GCancellable.
+ *
+ * You first create a #GWakeup with g_wakeup_new() and initialise a
+ * #GPollFD from it using g_wakeup_get_pollfd().  Polling on the created
+ * #GPollFD will block until g_wakeup_signal() is called, at which point
+ * it will immediately return.  Future attempts to poll will continue to
+ * return until g_wakeup_acknowledge() is called.  g_wakeup_free() is
+ * used to free a #GWakeup.
+ *
+ * On sufficiently modern Linux, this is implemented using eventfd.  On
+ * Windows it is implemented using an event handle.  On other systems it
+ * is implemented with a pair of pipes.
+ *
+ * Since: 2.30
+ **/
 #ifdef _WIN32
 
 #include <windows.h>
+
+#ifdef GLIB_COMPILATION
 #include "gmessages.h"
 #include "giochannel.h"
 #include "gwin32.h"
+#endif
 
 GWakeup *
 g_wakeup_new (void)
@@ -46,10 +83,10 @@ g_wakeup_new (void)
 
 void
 g_wakeup_get_pollfd (GWakeup *wakeup,
-                     GPollFD *fd)
+                     GPollFD *poll_fd)
 {
-  fd->fd = (gintptr) wakeup;
-  fd->events = G_IO_IN;
+  poll_fd->fd = (gintptr) wakeup;
+  poll_fd->events = G_IO_IN;
 }
 
 void
@@ -84,6 +121,17 @@ struct _GWakeup
   gint fds[2];
 };
 
+/**
+ * g_wakeup_new:
+ *
+ * Creates a new #GWakeup.
+ *
+ * You should use g_wakeup_free() to free it when you are done.
+ *
+ * Returns: a new #GWakeup
+ *
+ * Since: 2.30
+ **/
 GWakeup *
 g_wakeup_new (void)
 {
@@ -94,7 +142,11 @@ g_wakeup_new (void)
 
   /* try eventfd first, if we think we can */
 #if defined (HAVE_EVENTFD)
+#ifndef TEST_EVENTFD_FALLBACK
   wakeup->fds[0] = eventfd (0, EFD_CLOEXEC | EFD_NONBLOCK);
+#else
+  wakeup->fds[0] = -1;
+#endif
 
   if (wakeup->fds[0] != -1)
     {
@@ -115,14 +167,40 @@ g_wakeup_new (void)
   return wakeup;
 }
 
+/**
+ * g_wakeup_get_pollfd:
+ * @wakeup: a #GWakeup
+ * @poll_fd: a #GPollFD
+ *
+ * Prepares a @poll_fd such that polling on it will succeed when
+ * g_wakeup_signal() has been called on @wakeup.
+ *
+ * @poll_fd is valid until @wakeup is freed.
+ *
+ * Since: 2.30
+ **/
 void
 g_wakeup_get_pollfd (GWakeup *wakeup,
-                     GPollFD *fd)
+                     GPollFD *poll_fd)
 {
-  fd->fd = wakeup->fds[0];
-  fd->events = G_IO_IN;
+  poll_fd->fd = wakeup->fds[0];
+  poll_fd->events = G_IO_IN;
 }
 
+/**
+ * g_wakeup_acknowledge:
+ * @wakeup: a #GWakeup
+ *
+ * Acknowledges receipt of a wakeup signal on @wakeup.
+ *
+ * You must call this after @wakeup polls as ready.  If not, it will
+ * continue to poll as ready until you do so.
+ *
+ * If you call this function and @wakeup is not signaled, nothing
+ * happens.
+ *
+ * Since: 2.30
+ **/
 void
 g_wakeup_acknowledge (GWakeup *wakeup)
 {
@@ -132,17 +210,56 @@ g_wakeup_acknowledge (GWakeup *wakeup)
   while (read (wakeup->fds[0], buffer, sizeof buffer) == sizeof buffer);
 }
 
+/**
+ * g_wakeup_signal:
+ * @wakeup: a #GWakeup
+ *
+ * Signals @wakeup.
+ *
+ * Any future (or present) polling on the #GPollFD returned by
+ * g_wakeup_get_pollfd() will immediately succeed until such a time as
+ * g_wakeup_acknowledge() is called.
+ *
+ * This function is safe to call from a UNIX signal handler.
+ *
+ * Since: 2.30
+ **/
 void
 g_wakeup_signal (GWakeup *wakeup)
 {
-  guint64 one = 1;
+  int res;
 
   if (wakeup->fds[1] == -1)
-    write (wakeup->fds[0], &one, sizeof one);
+    {
+      guint64 one = 1;
+
+      /* eventfd() case. It requires a 64-bit counter increment value to be
+       * written. */
+      do
+        res = write (wakeup->fds[0], &one, sizeof one);
+      while (G_UNLIKELY (res == -1 && errno == EINTR));
+    }
   else
-    write (wakeup->fds[1], &one, 1);
+    {
+      guint8 one = 1;
+
+      /* Non-eventfd() case. Only a single byte needs to be written, and it can
+       * have an arbitrary value. */
+      do
+        res = write (wakeup->fds[1], &one, sizeof one);
+      while (G_UNLIKELY (res == -1 && errno == EINTR));
+    }
 }
 
+/**
+ * g_wakeup_free:
+ * @wakeup: a #GWakeup
+ *
+ * Frees @wakeup.
+ *
+ * You must not currently be polling on the #GPollFD returned by
+ * g_wakeup_get_pollfd(), or the result is undefined.
+ **/
 void
 g_wakeup_free (GWakeup *wakeup)
 {