Fix whitespace eob cleanup
[emacs.git] / src / xgselect.c
bloba9461a5df5a408781c323b93161d19eb91eaf87e
1 /* Function for handling the GLib event loop.
3 Copyright (C) 2009-2016 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or (at
10 your option) any later version.
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
20 #include <config.h>
22 #include "xgselect.h"
24 #ifdef HAVE_GLIB
26 #include <glib.h>
27 #include <errno.h>
28 #include "blockinput.h"
29 #include "systime.h"
31 /* `xg_select' is a `pselect' replacement. Why do we need a separate function?
32 1. Timeouts. Glib and Gtk rely on timer events. If we did pselect
33 with a greater timeout then the one scheduled by Glib, we would
34 not allow Glib to process its timer events. We want Glib to
35 work smoothly, so we need to reduce our timeout to match Glib.
36 2. Descriptors. Glib may listen to more file descriptors than we do.
37 So we add Glib descriptors to our pselect pool, but we don't change
38 the value returned by the function. The return value matches only
39 the descriptors passed as arguments, making it compatible with
40 plain pselect. */
42 int
43 xg_select (int fds_lim, fd_set *rfds, fd_set *wfds, fd_set *efds,
44 struct timespec const *timeout, sigset_t const *sigmask)
46 fd_set all_rfds, all_wfds;
47 struct timespec tmo;
48 struct timespec const *tmop = timeout;
50 GMainContext *context;
51 bool have_wfds = wfds != NULL;
52 GPollFD gfds_buf[128];
53 GPollFD *gfds = gfds_buf;
54 int gfds_size = ARRAYELTS (gfds_buf);
55 int n_gfds, retval = 0, our_fds = 0, max_fds = fds_lim - 1;
56 bool context_acquired = false;
57 int i, nfds, tmo_in_millisec, must_free = 0;
58 bool need_to_dispatch;
60 context = g_main_context_default ();
61 context_acquired = g_main_context_acquire (context);
62 /* FIXME: If we couldn't acquire the context, we just silently proceed
63 because this function handles more than just glib file descriptors.
64 Note that, as implemented, this failure is completely silent: there is
65 no feedback to the caller. */
67 if (rfds) all_rfds = *rfds;
68 else FD_ZERO (&all_rfds);
69 if (wfds) all_wfds = *wfds;
70 else FD_ZERO (&all_wfds);
72 n_gfds = (context_acquired
73 ? g_main_context_query (context, G_PRIORITY_LOW, &tmo_in_millisec,
74 gfds, gfds_size)
75 : -1);
77 if (gfds_size < n_gfds)
79 /* Avoid using SAFE_NALLOCA, as that implicitly refers to the
80 current thread. Using xnmalloc avoids thread-switching
81 problems here. */
82 gfds = xnmalloc (n_gfds, sizeof *gfds);
83 must_free = 1;
84 gfds_size = n_gfds;
85 n_gfds = g_main_context_query (context, G_PRIORITY_LOW, &tmo_in_millisec,
86 gfds, gfds_size);
89 for (i = 0; i < n_gfds; ++i)
91 if (gfds[i].events & G_IO_IN)
93 FD_SET (gfds[i].fd, &all_rfds);
94 if (gfds[i].fd > max_fds) max_fds = gfds[i].fd;
96 if (gfds[i].events & G_IO_OUT)
98 FD_SET (gfds[i].fd, &all_wfds);
99 if (gfds[i].fd > max_fds) max_fds = gfds[i].fd;
100 have_wfds = true;
104 if (must_free)
105 xfree (gfds);
107 if (n_gfds >= 0 && tmo_in_millisec >= 0)
109 tmo = make_timespec (tmo_in_millisec / 1000,
110 1000 * 1000 * (tmo_in_millisec % 1000));
111 if (!timeout || timespec_cmp (tmo, *timeout) < 0)
112 tmop = &tmo;
115 fds_lim = max_fds + 1;
116 nfds = pselect (fds_lim, &all_rfds, have_wfds ? &all_wfds : NULL,
117 efds, tmop, sigmask);
119 if (nfds < 0)
120 retval = nfds;
121 else if (nfds > 0)
123 for (i = 0; i < fds_lim; ++i)
125 if (FD_ISSET (i, &all_rfds))
127 if (rfds && FD_ISSET (i, rfds)) ++retval;
128 else ++our_fds;
130 else if (rfds)
131 FD_CLR (i, rfds);
133 if (have_wfds && FD_ISSET (i, &all_wfds))
135 if (wfds && FD_ISSET (i, wfds)) ++retval;
136 else ++our_fds;
138 else if (wfds)
139 FD_CLR (i, wfds);
141 if (efds && FD_ISSET (i, efds))
142 ++retval;
146 /* If Gtk+ is in use eventually gtk_main_iteration will be called,
147 unless retval is zero. */
148 #ifdef USE_GTK
149 need_to_dispatch = retval == 0;
150 #else
151 need_to_dispatch = true;
152 #endif
153 if (need_to_dispatch && context_acquired)
155 int pselect_errno = errno;
156 /* Prevent g_main_dispatch recursion, that would occur without
157 block_input wrapper, because event handlers call
158 unblock_input. Event loop recursion was causing Bug#15801. */
159 block_input ();
160 while (g_main_context_pending (context))
161 g_main_context_dispatch (context);
162 unblock_input ();
163 errno = pselect_errno;
166 if (context_acquired)
167 g_main_context_release (context);
169 /* To not have to recalculate timeout, return like this. */
170 if ((our_fds > 0 || (nfds == 0 && tmop == &tmo)) && (retval == 0))
172 retval = -1;
173 errno = EINTR;
176 return retval;
178 #endif /* HAVE_GLIB */