(root)/
glib-2.79.0/
glib/
gwakeup.c
       1  /*
       2   * Copyright © 2011 Canonical Limited
       3   *
       4   * SPDX-License-Identifier: LGPL-2.1-or-later
       5   *
       6   * This library is free software; you can redistribute it and/or
       7   * modify it under the terms of the GNU Lesser General Public
       8   * License as published by the Free Software Foundation; either
       9   * version 2.1 of the License, or (at your option) any later version.
      10   *
      11   * This library is distributed in the hope that it will be useful,
      12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14   * Lesser General Public License for more details.
      15   *
      16   * You should have received a copy of the GNU Lesser General Public
      17   * License along with this library; if not, see <http://www.gnu.org/licenses/>.
      18   *
      19   * Author: Ryan Lortie <desrt@desrt.ca>
      20   */
      21  
      22  #include "config.h"
      23  
      24  #include <stdint.h>
      25  
      26  /* gwakeup.c is special -- GIO and some test cases include it.  As such,
      27   * it cannot include other glib headers without triggering the single
      28   * includes warnings.  We have to manually include its dependencies here
      29   * (and at all other use sites).
      30   */
      31  #ifdef GLIB_COMPILATION
      32  #include "gtypes.h"
      33  #include "gpoll.h"
      34  #else
      35  #include <glib.h>
      36  #endif
      37  
      38  #include "gwakeup.h"
      39  
      40  /*< private >
      41   * GWakeup:
      42   *
      43   * `GWakeup` is a simple and portable way of signaling events between
      44   * different threads in a way that integrates nicely with g_poll().
      45   * GLib uses it internally for cross-thread signalling in the
      46   * implementation of #GMainContext and #GCancellable.
      47   *
      48   * You first create a #GWakeup with g_wakeup_new() and initialise a
      49   * #GPollFD from it using g_wakeup_get_pollfd().  Polling on the created
      50   * #GPollFD will block until g_wakeup_signal() is called, at which point
      51   * it will immediately return.  Future attempts to poll will continue to
      52   * return until g_wakeup_acknowledge() is called.  g_wakeup_free() is
      53   * used to free a #GWakeup.
      54   *
      55   * On sufficiently modern Linux, this is implemented using eventfd.  On
      56   * Windows it is implemented using an event handle.  On other systems it
      57   * is implemented with a pair of pipes.
      58   *
      59   * Since: 2.30
      60   */
      61  #ifdef _WIN32
      62  
      63  #include <windows.h>
      64  
      65  #ifdef GLIB_COMPILATION
      66  #include "gmessages.h"
      67  #include "giochannel.h"
      68  #include "gwin32.h"
      69  #endif
      70  
      71  GWakeup *
      72  g_wakeup_new (void)
      73  {
      74    HANDLE wakeup;
      75  
      76    wakeup = CreateEvent (NULL, TRUE, FALSE, NULL);
      77  
      78    if (wakeup == NULL)
      79      g_error ("Cannot create event for GWakeup: %s",
      80               g_win32_error_message (GetLastError ()));
      81  
      82    return (GWakeup *) wakeup;
      83  }
      84  
      85  void
      86  g_wakeup_get_pollfd (GWakeup *wakeup,
      87                       GPollFD *poll_fd)
      88  {
      89    poll_fd->fd = (gintptr) wakeup;
      90    poll_fd->events = G_IO_IN;
      91  }
      92  
      93  void
      94  g_wakeup_acknowledge (GWakeup *wakeup)
      95  {
      96    ResetEvent ((HANDLE) wakeup);
      97  }
      98  
      99  void
     100  g_wakeup_signal (GWakeup *wakeup)
     101  {
     102    SetEvent ((HANDLE) wakeup);
     103  }
     104  
     105  void
     106  g_wakeup_free (GWakeup *wakeup)
     107  {
     108    CloseHandle ((HANDLE) wakeup);
     109  }
     110  
     111  #else
     112  
     113  #include "glib-unix.h"
     114  #include <fcntl.h>
     115  
     116  #if defined (HAVE_EVENTFD)
     117  #include <sys/eventfd.h>
     118  #endif
     119  
     120  struct _GWakeup
     121  {
     122    gint fds[2];
     123  };
     124  
     125  /*< private >
     126   * g_wakeup_new:
     127   *
     128   * Creates a new #GWakeup.
     129   *
     130   * You should use g_wakeup_free() to free it when you are done.
     131   *
     132   * Returns: a new #GWakeup
     133   *
     134   * Since: 2.30
     135   **/
     136  GWakeup *
     137  g_wakeup_new (void)
     138  {
     139    GError *error = NULL;
     140    GWakeup *wakeup;
     141  
     142    wakeup = g_slice_new (GWakeup);
     143  
     144    /* try eventfd first, if we think we can */
     145  #if defined (HAVE_EVENTFD)
     146  #ifndef TEST_EVENTFD_FALLBACK
     147    wakeup->fds[0] = eventfd (0, EFD_CLOEXEC | EFD_NONBLOCK);
     148  #else
     149    wakeup->fds[0] = -1;
     150  #endif
     151  
     152    if (wakeup->fds[0] != -1)
     153      {
     154        wakeup->fds[1] = -1;
     155        return wakeup;
     156      }
     157  
     158    /* for any failure, try a pipe instead */
     159  #endif
     160  
     161    if (!g_unix_open_pipe (wakeup->fds, O_CLOEXEC | O_NONBLOCK, &error))
     162      g_error ("Creating pipes for GWakeup: %s", error->message);
     163  
     164    if (!g_unix_set_fd_nonblocking (wakeup->fds[0], TRUE, &error) ||
     165        !g_unix_set_fd_nonblocking (wakeup->fds[1], TRUE, &error))
     166      g_error ("Set pipes non-blocking for GWakeup: %s", error->message);
     167  
     168    return wakeup;
     169  }
     170  
     171  /*< private >
     172   * g_wakeup_get_pollfd:
     173   * @wakeup: a #GWakeup
     174   * @poll_fd: a #GPollFD
     175   *
     176   * Prepares a @poll_fd such that polling on it will succeed when
     177   * g_wakeup_signal() has been called on @wakeup.
     178   *
     179   * @poll_fd is valid until @wakeup is freed.
     180   *
     181   * Since: 2.30
     182   **/
     183  void
     184  g_wakeup_get_pollfd (GWakeup *wakeup,
     185                       GPollFD *poll_fd)
     186  {
     187    poll_fd->fd = wakeup->fds[0];
     188    poll_fd->events = G_IO_IN;
     189  }
     190  
     191  /*< private >
     192   * g_wakeup_acknowledge:
     193   * @wakeup: a #GWakeup
     194   *
     195   * Acknowledges receipt of a wakeup signal on @wakeup.
     196   *
     197   * You must call this after @wakeup polls as ready.  If not, it will
     198   * continue to poll as ready until you do so.
     199   *
     200   * If you call this function and @wakeup is not signaled, nothing
     201   * happens.
     202   *
     203   * Since: 2.30
     204   **/
     205  void
     206  g_wakeup_acknowledge (GWakeup *wakeup)
     207  {
     208    int res;
     209  
     210    if (wakeup->fds[1] == -1)
     211      {
     212        uint64_t value;
     213  
     214        /* eventfd() read resets counter */
     215        do
     216          res = read (wakeup->fds[0], &value, sizeof (value));
     217        while (G_UNLIKELY (res == -1 && errno == EINTR));
     218      }
     219    else
     220      {
     221        uint8_t value;
     222  
     223        /* read until it is empty */
     224        do
     225          res = read (wakeup->fds[0], &value, sizeof (value));
     226        while (res == sizeof (value) || G_UNLIKELY (res == -1 && errno == EINTR));
     227      }
     228  }
     229  
     230  /*< private >
     231   * g_wakeup_signal:
     232   * @wakeup: a #GWakeup
     233   *
     234   * Signals @wakeup.
     235   *
     236   * Any future (or present) polling on the #GPollFD returned by
     237   * g_wakeup_get_pollfd() will immediately succeed until such a time as
     238   * g_wakeup_acknowledge() is called.
     239   *
     240   * This function is safe to call from a UNIX signal handler.
     241   *
     242   * Since: 2.30
     243   **/
     244  void
     245  g_wakeup_signal (GWakeup *wakeup)
     246  {
     247    int res;
     248  
     249    if (wakeup->fds[1] == -1)
     250      {
     251        uint64_t one = 1;
     252  
     253        /* eventfd() case. It requires a 64-bit counter increment value to be
     254         * written. */
     255        do
     256          res = write (wakeup->fds[0], &one, sizeof one);
     257        while (G_UNLIKELY (res == -1 && errno == EINTR));
     258      }
     259    else
     260      {
     261        uint8_t one = 1;
     262  
     263        /* Non-eventfd() case. Only a single byte needs to be written, and it can
     264         * have an arbitrary value. */
     265        do
     266          res = write (wakeup->fds[1], &one, sizeof one);
     267        while (G_UNLIKELY (res == -1 && errno == EINTR));
     268      }
     269  }
     270  
     271  /*< private >
     272   * g_wakeup_free:
     273   * @wakeup: a #GWakeup
     274   *
     275   * Frees @wakeup.
     276   *
     277   * You must not currently be polling on the #GPollFD returned by
     278   * g_wakeup_get_pollfd(), or the result is undefined.
     279   **/
     280  void
     281  g_wakeup_free (GWakeup *wakeup)
     282  {
     283    close (wakeup->fds[0]);
     284  
     285    if (wakeup->fds[1] != -1)
     286      close (wakeup->fds[1]);
     287  
     288    g_slice_free (GWakeup, wakeup);
     289  }
     290  
     291  #endif /* !_WIN32 */