This source file includes following definitions.
- release_select_lock
- acquire_select_lock
- suppress_xg_select
- release_xg_select
- xg_select
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 #include <config.h>
21
22 #include "xgselect.h"
23
24 #ifdef HAVE_GLIB
25
26 #include <glib.h>
27 #include <errno.h>
28 #include "lisp.h"
29 #include "blockinput.h"
30 #include "systime.h"
31 #include "process.h"
32
33 static ptrdiff_t threads_holding_glib_lock;
34 static GMainContext *glib_main_context;
35
36
37 static int xg_select_suppress_count;
38
39 void
40 release_select_lock (void)
41 {
42 #if GNUC_PREREQ (4, 7, 0)
43 if (__atomic_sub_fetch (&threads_holding_glib_lock, 1, __ATOMIC_ACQ_REL) == 0)
44 g_main_context_release (glib_main_context);
45 #else
46 if (--threads_holding_glib_lock == 0)
47 g_main_context_release (glib_main_context);
48 #endif
49 }
50
51 static void
52 acquire_select_lock (GMainContext *context)
53 {
54 #if GNUC_PREREQ (4, 7, 0)
55 if (__atomic_fetch_add (&threads_holding_glib_lock, 1, __ATOMIC_ACQ_REL) == 0)
56 {
57 glib_main_context = context;
58 while (!g_main_context_acquire (context))
59 {
60
61 }
62 }
63 #else
64 if (threads_holding_glib_lock++ == 0)
65 {
66 glib_main_context = context;
67 while (!g_main_context_acquire (context))
68 {
69
70 }
71 }
72 #endif
73 }
74
75
76
77 void
78 suppress_xg_select (void)
79 {
80 ++xg_select_suppress_count;
81 }
82
83 void
84 release_xg_select (void)
85 {
86 if (!xg_select_suppress_count)
87 emacs_abort ();
88
89 --xg_select_suppress_count;
90 }
91
92
93
94
95
96
97
98
99
100
101
102
103 int
104 xg_select (int fds_lim, fd_set *rfds, fd_set *wfds, fd_set *efds,
105 struct timespec *timeout, sigset_t *sigmask)
106 {
107 fd_set all_rfds, all_wfds;
108 struct timespec tmo;
109 struct timespec *tmop = timeout;
110
111 GMainContext *context;
112 bool have_wfds = wfds != NULL;
113 GPollFD gfds_buf[128];
114 GPollFD *gfds = gfds_buf;
115 int gfds_size = ARRAYELTS (gfds_buf);
116 int n_gfds, retval = 0, our_fds = 0, max_fds = fds_lim - 1;
117 int i, nfds, tmo_in_millisec, must_free = 0;
118 bool need_to_dispatch;
119 #ifdef USE_GTK
120 bool already_has_events;
121 #endif
122
123 if (xg_select_suppress_count)
124 return pselect (fds_lim, rfds, wfds, efds, timeout, sigmask);
125
126 context = g_main_context_default ();
127 acquire_select_lock (context);
128
129 #ifdef USE_GTK
130 already_has_events = g_main_context_pending (context);
131 #ifndef HAVE_PGTK
132 already_has_events = already_has_events && x_gtk_use_native_input;
133 #endif
134 #endif
135
136 if (rfds) all_rfds = *rfds;
137 else FD_ZERO (&all_rfds);
138 if (wfds) all_wfds = *wfds;
139 else FD_ZERO (&all_wfds);
140
141 n_gfds = g_main_context_query (context, G_PRIORITY_LOW, &tmo_in_millisec,
142 gfds, gfds_size);
143
144 if (gfds_size < n_gfds)
145 {
146
147
148
149 gfds = xnmalloc (n_gfds, sizeof *gfds);
150 must_free = 1;
151 gfds_size = n_gfds;
152 n_gfds = g_main_context_query (context, G_PRIORITY_LOW, &tmo_in_millisec,
153 gfds, gfds_size);
154 }
155
156 for (i = 0; i < n_gfds; ++i)
157 {
158 if (gfds[i].events & G_IO_IN)
159 {
160 FD_SET (gfds[i].fd, &all_rfds);
161 if (gfds[i].fd > max_fds) max_fds = gfds[i].fd;
162 }
163 if (gfds[i].events & G_IO_OUT)
164 {
165 FD_SET (gfds[i].fd, &all_wfds);
166 if (gfds[i].fd > max_fds) max_fds = gfds[i].fd;
167 have_wfds = true;
168 }
169 }
170
171 if (must_free)
172 xfree (gfds);
173
174 if (n_gfds >= 0 && tmo_in_millisec >= 0)
175 {
176 tmo = make_timespec (tmo_in_millisec / 1000,
177 1000 * 1000 * (tmo_in_millisec % 1000));
178 if (!timeout || timespec_cmp (tmo, *timeout) < 0)
179 tmop = &tmo;
180 }
181
182 #ifndef USE_GTK
183 fds_lim = max_fds + 1;
184 nfds = thread_select (pselect, fds_lim,
185 &all_rfds, have_wfds ? &all_wfds : NULL, efds,
186 tmop, sigmask);
187 #else
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202 if (!already_has_events)
203 {
204 fds_lim = max_fds + 1;
205 nfds = thread_select (pselect, fds_lim,
206 &all_rfds, have_wfds ? &all_wfds : NULL, efds,
207 tmop, sigmask);
208 }
209 else
210 {
211
212 nfds = 1;
213 FD_ZERO (&all_rfds);
214 if (have_wfds)
215 FD_ZERO (&all_wfds);
216 if (efds)
217 FD_ZERO (efds);
218 our_fds++;
219 }
220 #endif
221
222 if (nfds < 0)
223 retval = nfds;
224 else if (nfds > 0)
225 {
226 for (i = 0; i < fds_lim; ++i)
227 {
228 if (FD_ISSET (i, &all_rfds))
229 {
230 if (rfds && FD_ISSET (i, rfds)) ++retval;
231 else ++our_fds;
232 }
233 else if (rfds)
234 FD_CLR (i, rfds);
235
236 if (have_wfds && FD_ISSET (i, &all_wfds))
237 {
238 if (wfds && FD_ISSET (i, wfds)) ++retval;
239 else ++our_fds;
240 }
241 else if (wfds)
242 FD_CLR (i, wfds);
243
244 if (efds && FD_ISSET (i, efds))
245 ++retval;
246 }
247 }
248
249
250
251 #ifdef USE_GTK
252 need_to_dispatch = retval == 0;
253 #else
254 need_to_dispatch = true;
255 #endif
256
257
258
259
260
261
262
263
264
265
266
267 #ifdef HAVE_XWIDGETS
268 catch_child_signal ();
269 #endif
270
271 if (need_to_dispatch)
272 {
273 acquire_select_lock (context);
274
275 int pselect_errno = errno;
276
277
278
279 block_input ();
280 while (g_main_context_pending (context))
281 g_main_context_dispatch (context);
282 unblock_input ();
283 errno = pselect_errno;
284 release_select_lock ();
285 }
286
287
288 if ((our_fds > 0 || (nfds == 0 && tmop == &tmo)) && (retval == 0))
289 {
290 retval = -1;
291 errno = EINTR;
292 }
293
294 return retval;
295 }
296 #endif