LCOV - code coverage report
Current view: top level - glib - gwakeup.c (source / functions) Coverage Total Hit
Test: unnamed Lines: 95.0 % 40 38
Test Date: 2025-01-07 05:22:06 Functions: 100.0 % 5 5
Branches: - 0 0

             Branch data     Line data    Source code
       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                 :       24884 : g_wakeup_new (void)
     138                 :             : {
     139                 :       24884 :   GError *error = NULL;
     140                 :             :   GWakeup *wakeup;
     141                 :             : 
     142                 :       24884 :   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                 :       24829 :   wakeup->fds[0] = eventfd (0, EFD_CLOEXEC | EFD_NONBLOCK);
     148                 :             : #else
     149                 :          55 :   wakeup->fds[0] = -1;
     150                 :             : #endif
     151                 :             : 
     152                 :       24884 :   if (wakeup->fds[0] != -1)
     153                 :             :     {
     154                 :       24829 :       wakeup->fds[1] = -1;
     155                 :       24829 :       return wakeup;
     156                 :             :     }
     157                 :             : 
     158                 :             :   /* for any failure, try a pipe instead */
     159                 :             : #endif
     160                 :             : 
     161                 :          55 :   if (!g_unix_open_pipe (wakeup->fds, O_CLOEXEC | O_NONBLOCK, &error))
     162                 :           0 :     g_error ("Creating pipes for GWakeup: %s", error->message);
     163                 :             : 
     164                 :         110 :   if (!g_unix_set_fd_nonblocking (wakeup->fds[0], TRUE, &error) ||
     165                 :          55 :       !g_unix_set_fd_nonblocking (wakeup->fds[1], TRUE, &error))
     166                 :           0 :     g_error ("Set pipes non-blocking for GWakeup: %s", error->message);
     167                 :             : 
     168                 :          55 :   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                 :      958170 : g_wakeup_get_pollfd (GWakeup *wakeup,
     185                 :             :                      GPollFD *poll_fd)
     186                 :             : {
     187                 :      958170 :   poll_fd->fd = wakeup->fds[0];
     188                 :      958170 :   poll_fd->events = G_IO_IN;
     189                 :      958170 : }
     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                 :     1274710 : g_wakeup_acknowledge (GWakeup *wakeup)
     207                 :             : {
     208                 :             :   int res;
     209                 :             : 
     210                 :     1274710 :   if (wakeup->fds[1] == -1)
     211                 :             :     {
     212                 :             :       uint64_t value;
     213                 :             : 
     214                 :             :       /* eventfd() read resets counter */
     215                 :             :       do
     216                 :      805707 :         res = read (wakeup->fds[0], &value, sizeof (value));
     217                 :      805707 :       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                 :     1034590 :         res = read (wakeup->fds[0], &value, sizeof (value));
     226                 :     1034590 :       while (res == sizeof (value) || G_UNLIKELY (res == -1 && errno == EINTR));
     227                 :             :     }
     228                 :     1274710 : }
     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                 :     3681906 : g_wakeup_signal (GWakeup *wakeup)
     246                 :             : {
     247                 :             :   int res;
     248                 :             : 
     249                 :     3681906 :   if (wakeup->fds[1] == -1)
     250                 :             :     {
     251                 :     2181853 :       uint64_t one = 1;
     252                 :             : 
     253                 :             :       /* eventfd() case. It requires a 64-bit counter increment value to be
     254                 :             :        * written. */
     255                 :             :       do
     256                 :     2181853 :         res = write (wakeup->fds[0], &one, sizeof one);
     257                 :     2181853 :       while (G_UNLIKELY (res == -1 && errno == EINTR));
     258                 :             :     }
     259                 :             :   else
     260                 :             :     {
     261                 :     1500053 :       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                 :     1500053 :         res = write (wakeup->fds[1], &one, sizeof one);
     267                 :     1500053 :       while (G_UNLIKELY (res == -1 && errno == EINTR));
     268                 :             :     }
     269                 :     3681906 : }
     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                 :       24347 : g_wakeup_free (GWakeup *wakeup)
     282                 :             : {
     283                 :       24347 :   close (wakeup->fds[0]);
     284                 :             : 
     285                 :       24347 :   if (wakeup->fds[1] != -1)
     286                 :          55 :     close (wakeup->fds[1]);
     287                 :             : 
     288                 :       24347 :   g_slice_free (GWakeup, wakeup);
     289                 :       24347 : }
     290                 :             : 
     291                 :             : #endif /* !_WIN32 */
        

Generated by: LCOV version 2.0-1