Add GWakeup
[platform/upstream/glib.git] / glib / gwakeup.c
1 /*
2  * Copyright © 2011 Canonical Limited
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the licence, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  *
19  * Author: Ryan Lortie <desrt@desrt.ca>
20  */
21
22 #include "config.h"
23
24 #include "gwakeup.h"
25
26 #ifdef _WIN32
27
28 #include <windows.h>
29 #include "gmessages.h"
30 #include "giochannel.h"
31 #include "gwin32.h"
32
33 GWakeup *
34 g_wakeup_new (void)
35 {
36   HANDLE wakeup;
37
38   wakeup = CreateEvent (NULL, TRUE, FALSE, NULL);
39
40   if (wakeup == NULL)
41     g_error ("Cannot create event for GWakeup: %s",
42              g_win32_error_message (GetLastError ()));
43
44   return (GWakeup *) wakeup;
45 }
46
47 void
48 g_wakeup_get_pollfd (GWakeup *wakeup,
49                      GPollFD *fd)
50 {
51   fd->fd = (gintptr) wakeup;
52   fd->events = G_IO_IN;
53 }
54
55 void
56 g_wakeup_acknowledge (GWakeup *wakeup)
57 {
58   ResetEvent ((HANDLE) wakeup);
59 }
60
61 void
62 g_wakeup_signal (GWakeup *wakeup)
63 {
64   SetEvent ((HANDLE) wakeup);
65 }
66
67 void
68 g_wakeup_free (GWakeup *wakeup)
69 {
70   CloseHandle ((HANDLE) wakeup);
71 }
72
73 #else
74
75 #include "glib-unix.h"
76 #include <fcntl.h>
77
78 #if defined (HAVE_EVENTFD)
79 #include <sys/eventfd.h>
80 #endif
81
82 struct _GWakeup
83 {
84   gint fds[2];
85 };
86
87 GWakeup *
88 g_wakeup_new (void)
89 {
90   GError *error = NULL;
91   GWakeup *wakeup;
92
93   wakeup = g_slice_new (GWakeup);
94
95   /* try eventfd first, if we think we can */
96 #if defined (HAVE_EVENTFD)
97   wakeup->fds[0] = eventfd (0, EFD_CLOEXEC | EFD_NONBLOCK);
98
99   if (wakeup->fds[0] != -1)
100     {
101       wakeup->fds[1] = -1;
102       return wakeup;
103     }
104
105   /* for any failure, try a pipe instead */
106 #endif
107
108   if (!g_unix_open_pipe (wakeup->fds, FD_CLOEXEC, &error))
109     g_error ("Creating pipes for GWakeup: %s\n", error->message);
110
111   if (!g_unix_set_fd_nonblocking (wakeup->fds[0], TRUE, &error) ||
112       !g_unix_set_fd_nonblocking (wakeup->fds[1], TRUE, &error))
113     g_error ("Set pipes non-blocking for GWakeup: %s\n", error->message);
114
115   return wakeup;
116 }
117
118 void
119 g_wakeup_get_pollfd (GWakeup *wakeup,
120                      GPollFD *fd)
121 {
122   fd->fd = wakeup->fds[0];
123   fd->events = G_IO_IN;
124 }
125
126 void
127 g_wakeup_acknowledge (GWakeup *wakeup)
128 {
129   char buffer[16];
130
131   /* read until it is empty */
132   while (read (wakeup->fds[0], buffer, sizeof buffer) == sizeof buffer);
133 }
134
135 void
136 g_wakeup_signal (GWakeup *wakeup)
137 {
138   guint64 one = 1;
139
140   if (wakeup->fds[1] == -1)
141     write (wakeup->fds[0], &one, sizeof one);
142   else
143     write (wakeup->fds[1], &one, 1);
144 }
145
146 void
147 g_wakeup_free (GWakeup *wakeup)
148 {
149   close (wakeup->fds[0]);
150
151   if (wakeup->fds[1] != -1)
152     close (wakeup->fds[1]);
153
154   g_slice_free (GWakeup, wakeup);
155 }
156
157 #endif /* !_WIN32 */