* lisp/progmodes/hideif.el: Use lexical-binding. Fix up cl-lib usage.
[bpt/emacs.git] / src / xgselect.c
CommitLineData
872870b2 1/* Function for handling the GLib event loop.
95df8112 2
ba318903 3Copyright (C) 2009-2014 Free Software Foundation, Inc.
872870b2
JD
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or
10(at your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
a2332e8d 18along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
872870b2 19
08a494a3 20#include <config.h>
872870b2 21
aefd87e1
PE
22#include "xgselect.h"
23
55a87246 24#ifdef HAVE_GLIB
aefd87e1 25
872870b2
JD
26#include <glib.h>
27#include <errno.h>
e6e8a5eb 28#include <stdbool.h>
43aac990 29#include <timespec.h>
7452b7bd 30#include "frame.h"
6709d4da
JC
31#include "blockinput.h"
32
33/* `xg_select' is a `pselect' replacement. Why do we need a separate function?
34 1. Timeouts. Glib and Gtk rely on timer events. If we did pselect
35 with a greater timeout then the one scheduled by Glib, we would
36 not allow Glib to process its timer events. We want Glib to
37 work smoothly, so we need to reduce our timeout to match Glib.
38 2. Descriptors. Glib may listen to more file descriptors than we do.
39 So we add Glib descriptors to our pselect pool, but we don't change
40 the value returned by the function. The return value matches only
41 the descriptors passed as arguments, making it compatible with
42 plain pselect. */
872870b2 43
872870b2 44int
d486344e 45xg_select (int fds_lim, fd_set *rfds, fd_set *wfds, fd_set *efds,
43aac990 46 struct timespec const *timeout, sigset_t const *sigmask)
872870b2 47{
d486344e 48 fd_set all_rfds, all_wfds;
43aac990
PE
49 struct timespec tmo;
50 struct timespec const *tmop = timeout;
872870b2 51
b0572523 52 GMainContext *context;
872870b2 53 int have_wfds = wfds != NULL;
0f46bc75
PE
54 GPollFD gfds_buf[128];
55 GPollFD *gfds = gfds_buf;
faa52174 56 int gfds_size = ARRAYELTS (gfds_buf);
0f46bc75 57 int n_gfds, retval = 0, our_fds = 0, max_fds = fds_lim - 1;
ff23cd9f 58 int i, nfds, tmo_in_millisec;
e6e8a5eb 59 bool need_to_dispatch;
0f46bc75 60 USE_SAFE_ALLOCA;
872870b2 61
5de0e011 62 context = g_main_context_default ();
b0572523 63
ae1d87e2 64 if (rfds) all_rfds = *rfds;
872870b2 65 else FD_ZERO (&all_rfds);
ae1d87e2 66 if (wfds) all_wfds = *wfds;
872870b2
JD
67 else FD_ZERO (&all_wfds);
68
0f46bc75
PE
69 n_gfds = g_main_context_query (context, G_PRIORITY_LOW, &tmo_in_millisec,
70 gfds, gfds_size);
71 if (gfds_size < n_gfds)
72 {
73 SAFE_NALLOCA (gfds, sizeof *gfds, n_gfds);
74 gfds_size = n_gfds;
75 n_gfds = g_main_context_query (context, G_PRIORITY_LOW, &tmo_in_millisec,
76 gfds, gfds_size);
77 }
872870b2 78
41729b81 79 for (i = 0; i < n_gfds; ++i)
872870b2
JD
80 {
81 if (gfds[i].events & G_IO_IN)
82 {
83 FD_SET (gfds[i].fd, &all_rfds);
84 if (gfds[i].fd > max_fds) max_fds = gfds[i].fd;
85 }
86 if (gfds[i].events & G_IO_OUT)
87 {
88 FD_SET (gfds[i].fd, &all_wfds);
89 if (gfds[i].fd > max_fds) max_fds = gfds[i].fd;
90 have_wfds = 1;
91 }
92 }
93
0f46bc75
PE
94 SAFE_FREE ();
95
872870b2
JD
96 if (tmo_in_millisec >= 0)
97 {
43aac990
PE
98 tmo = make_timespec (tmo_in_millisec / 1000,
99 1000 * 1000 * (tmo_in_millisec % 1000));
100 if (!timeout || timespec_cmp (tmo, *timeout) < 0)
d35af63c 101 tmop = &tmo;
872870b2
JD
102 }
103
97107e2e 104 fds_lim = max_fds + 1;
d35af63c
PE
105 nfds = pselect (fds_lim, &all_rfds, have_wfds ? &all_wfds : NULL,
106 efds, tmop, sigmask);
872870b2
JD
107
108 if (nfds < 0)
109 retval = nfds;
41729b81 110 else if (nfds > 0)
872870b2 111 {
97107e2e 112 for (i = 0; i < fds_lim; ++i)
872870b2
JD
113 {
114 if (FD_ISSET (i, &all_rfds))
115 {
116 if (rfds && FD_ISSET (i, rfds)) ++retval;
117 else ++our_fds;
118 }
42d3022b
J
119 else if (rfds)
120 FD_CLR (i, rfds);
121
872870b2
JD
122 if (have_wfds && FD_ISSET (i, &all_wfds))
123 {
124 if (wfds && FD_ISSET (i, wfds)) ++retval;
125 else ++our_fds;
126 }
42d3022b
J
127 else if (wfds)
128 FD_CLR (i, wfds);
129
872870b2
JD
130 if (efds && FD_ISSET (i, efds))
131 ++retval;
132 }
133 }
134
86d2bf49
MA
135 /* If Gtk+ is in use eventually gtk_main_iteration will be called,
136 unless retval is zero. */
872870b2 137#ifdef USE_GTK
e6e8a5eb
PE
138 need_to_dispatch = retval == 0;
139#else
140 need_to_dispatch = true;
872870b2 141#endif
e6e8a5eb
PE
142 if (need_to_dispatch)
143 {
144 int pselect_errno = errno;
6709d4da
JC
145 /* Prevent g_main_dispatch recursion, that would occur without
146 block_input wrapper, because event handlers call
147 unblock_input. Event loop recursion was causing Bug#15801. */
148 block_input ();
e6e8a5eb 149 while (g_main_context_pending (context))
6709d4da
JC
150 g_main_context_dispatch (context);
151 unblock_input ();
e6e8a5eb
PE
152 errno = pselect_errno;
153 }
872870b2 154
86d2bf49
MA
155 /* To not have to recalculate timeout, return like this. */
156 if ((our_fds > 0 || (nfds == 0 && tmop == &tmo)) && (retval == 0))
157 {
158 retval = -1;
159 errno = EINTR;
872870b2
JD
160 }
161
162 return retval;
163}
55a87246 164#endif /* HAVE_GLIB */