1 /* Function for handling the GLib event loop.
3 Copyright (C) 2009-2014 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
10 (at 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/>. */
31 #include "blockinput.h"
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
45 xg_select (int fds_lim
, fd_set
*rfds
, fd_set
*wfds
, fd_set
*efds
,
46 struct timespec
const *timeout
, sigset_t
const *sigmask
)
48 fd_set all_rfds
, all_wfds
;
50 struct timespec
const *tmop
= timeout
;
52 GMainContext
*context
;
53 int have_wfds
= wfds
!= NULL
;
54 GPollFD gfds_buf
[128];
55 GPollFD
*gfds
= gfds_buf
;
56 int gfds_size
= sizeof gfds_buf
/ sizeof *gfds_buf
;
57 int n_gfds
, retval
= 0, our_fds
= 0, max_fds
= fds_lim
- 1;
58 bool context_acquired
= false;
59 int i
, nfds
, tmo_in_millisec
= -1;
60 bool need_to_dispatch
;
63 context
= g_main_context_default ();
64 context_acquired
= g_main_context_acquire (context
);
65 /* FIXME: If we couldn't acquire the context, we just silently proceed
66 because this function handles more than just glib file descriptors.
67 Note that, as implemented, this failure is completely silent: there is
68 no feedback to the caller. */
70 if (rfds
) all_rfds
= *rfds
;
71 else FD_ZERO (&all_rfds
);
72 if (wfds
) all_wfds
= *wfds
;
73 else FD_ZERO (&all_wfds
);
75 n_gfds
= (context_acquired
76 ? g_main_context_query (context
, G_PRIORITY_LOW
, &tmo_in_millisec
,
80 if (gfds_size
< n_gfds
)
82 SAFE_NALLOCA (gfds
, sizeof *gfds
, n_gfds
);
84 n_gfds
= g_main_context_query (context
, G_PRIORITY_LOW
, &tmo_in_millisec
,
88 for (i
= 0; i
< n_gfds
; ++i
)
90 if (gfds
[i
].events
& G_IO_IN
)
92 FD_SET (gfds
[i
].fd
, &all_rfds
);
93 if (gfds
[i
].fd
> max_fds
) max_fds
= gfds
[i
].fd
;
95 if (gfds
[i
].events
& G_IO_OUT
)
97 FD_SET (gfds
[i
].fd
, &all_wfds
);
98 if (gfds
[i
].fd
> max_fds
) max_fds
= gfds
[i
].fd
;
105 if (tmo_in_millisec
>= 0)
107 tmo
= make_timespec (tmo_in_millisec
/ 1000,
108 1000 * 1000 * (tmo_in_millisec
% 1000));
109 if (!timeout
|| timespec_cmp (tmo
, *timeout
) < 0)
113 fds_lim
= max_fds
+ 1;
114 nfds
= pselect (fds_lim
, &all_rfds
, have_wfds
? &all_wfds
: NULL
,
115 efds
, tmop
, sigmask
);
121 for (i
= 0; i
< fds_lim
; ++i
)
123 if (FD_ISSET (i
, &all_rfds
))
125 if (rfds
&& FD_ISSET (i
, rfds
)) ++retval
;
131 if (have_wfds
&& FD_ISSET (i
, &all_wfds
))
133 if (wfds
&& FD_ISSET (i
, wfds
)) ++retval
;
139 if (efds
&& FD_ISSET (i
, efds
))
144 /* If Gtk+ is in use eventually gtk_main_iteration will be called,
145 unless retval is zero. */
147 need_to_dispatch
= retval
== 0;
149 need_to_dispatch
= true;
151 if (need_to_dispatch
)
153 int pselect_errno
= errno
;
154 /* Prevent g_main_dispatch recursion, that would occur without
155 block_input wrapper, because event handlers call
156 unblock_input. Event loop recursion was causing Bug#15801. */
158 while (g_main_context_pending (context
))
159 g_main_context_dispatch (context
);
161 errno
= pselect_errno
;
164 if (context_acquired
)
165 g_main_context_release (context
);
167 /* To not have to recalculate timeout, return like this. */
168 if ((our_fds
> 0 || (nfds
== 0 && tmop
== &tmo
)) && (retval
== 0))
176 #endif /* HAVE_GLIB */