1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4
5 #include <stdlib.h>
6 #include <stdio.h>
7 #ifdef HAVE_SYS_SOCKET_H
8 # include <sys/socket.h>
9 #endif
10 #ifdef _WIN32
11 # include <ws2tcpip.h>
12 #endif
13 #ifdef HAVE_NETDB_H
14 # include <netdb.h>
15 #endif
16 #ifdef HAVE_NETINET_IN_H
17 # include <netinet/in.h>
18 #endif
19
20 #include "Ecore.h"
21 #include "ecore_private.h"
22
23 #ifdef HAVE_GLIB
24 # include <glib.h>
25
26 static Eina_Bool _ecore_glib_active = EINA_FALSE;
27 static Ecore_Select_Function _ecore_glib_select_original;
28 static GPollFD *_ecore_glib_fds = NULL;
29 static size_t _ecore_glib_fds_size = 0;
30 static const size_t ECORE_GLIB_FDS_INITIAL = 128;
31 static const size_t ECORE_GLIB_FDS_STEP = 8;
32 static const size_t ECORE_GLIB_FDS_MAX_FREE = 256;
33 #if GLIB_CHECK_VERSION(2,32,0)
34 static GRecMutex *_ecore_glib_select_lock;
35 #else
36 static GStaticRecMutex *_ecore_glib_select_lock;
37 #endif
38
39 static Eina_Bool
_ecore_glib_fds_resize(size_t size)40 _ecore_glib_fds_resize(size_t size)
41 {
42 void *tmp = realloc(_ecore_glib_fds, sizeof(GPollFD) * size);
43
44 if (!tmp)
45 {
46 ERR("Could not realloc from %zu to %zu buckets.",
47 _ecore_glib_fds_size, size);
48 return EINA_FALSE;
49 }
50
51 _ecore_glib_fds = tmp;
52 _ecore_glib_fds_size = size;
53 return EINA_TRUE;
54 }
55
56 static int
_ecore_glib_context_query(GMainContext * ctx,int priority,int * p_timer)57 _ecore_glib_context_query(GMainContext *ctx,
58 int priority,
59 int *p_timer)
60 {
61 int reqfds;
62
63 if (_ecore_glib_fds_size == 0)
64 {
65 if (!_ecore_glib_fds_resize(ECORE_GLIB_FDS_INITIAL)) return -1;
66 }
67
68 while (1)
69 {
70 size_t size;
71
72 reqfds = g_main_context_query
73 (ctx, priority, p_timer, _ecore_glib_fds, _ecore_glib_fds_size);
74 if (reqfds <= (int)_ecore_glib_fds_size) break;
75
76 size = (1 + reqfds / ECORE_GLIB_FDS_STEP) * ECORE_GLIB_FDS_STEP;
77 if (!_ecore_glib_fds_resize(size)) return -1;
78 }
79
80 if (reqfds + ECORE_GLIB_FDS_MAX_FREE < _ecore_glib_fds_size)
81 {
82 size_t size;
83
84 size = (1 + reqfds / ECORE_GLIB_FDS_MAX_FREE) * ECORE_GLIB_FDS_MAX_FREE;
85 _ecore_glib_fds_resize(size);
86 }
87
88 return reqfds;
89 }
90
91 static int
_ecore_glib_context_poll_from(const GPollFD * pfds,int count,fd_set * rfds,fd_set * wfds,fd_set * efds)92 _ecore_glib_context_poll_from(const GPollFD *pfds,
93 int count,
94 fd_set *rfds,
95 fd_set *wfds,
96 fd_set *efds)
97 {
98 const GPollFD *itr = pfds, *itr_end = pfds + count;
99 int glib_fds = -1;
100
101 for (; itr < itr_end; itr++)
102 {
103 if (glib_fds < itr->fd)
104 glib_fds = itr->fd;
105
106 if (itr->events & G_IO_IN)
107 FD_SET(itr->fd, rfds);
108 if (itr->events & G_IO_OUT)
109 FD_SET(itr->fd, wfds);
110 if (itr->events & (G_IO_HUP | G_IO_ERR))
111 FD_SET(itr->fd, efds);
112 }
113
114 return glib_fds + 1;
115 }
116
117 static int
_ecore_glib_context_poll_to(GPollFD * pfds,int count,const fd_set * rfds,const fd_set * wfds,const fd_set * efds,int ready)118 _ecore_glib_context_poll_to(GPollFD *pfds,
119 int count,
120 const fd_set *rfds,
121 const fd_set *wfds,
122 const fd_set *efds,
123 int ready)
124 {
125 GPollFD *itr = pfds, *itr_end = pfds + count;
126 struct stat st;
127
128 for (; (itr < itr_end) && (ready > 0); itr++)
129 {
130 itr->revents = 0;
131 if (FD_ISSET(itr->fd, rfds) && (itr->events & G_IO_IN))
132 {
133 itr->revents |= G_IO_IN;
134 ready--;
135 }
136 if (FD_ISSET(itr->fd, wfds) && (itr->events & G_IO_OUT))
137 {
138 itr->revents |= G_IO_OUT;
139 ready--;
140 if (!fstat(itr->fd, &st))
141 {
142 if (S_ISSOCK(st.st_mode))
143 {
144 struct sockaddr_in peer;
145 socklen_t length = sizeof(peer);
146
147 memset(&peer, 0, sizeof(peer));
148 if (getpeername(itr->fd, (struct sockaddr *)&peer,
149 &length))
150 itr->revents |= G_IO_ERR;
151 }
152 }
153 }
154 if (FD_ISSET(itr->fd, efds) && (itr->events & (G_IO_HUP | G_IO_ERR)))
155 {
156 itr->revents |= G_IO_ERR;
157 ready--;
158 }
159 }
160 return ready;
161 }
162
163 static int
_ecore_glib_select__locked(GMainContext * ctx,int ecore_fds,fd_set * rfds,fd_set * wfds,fd_set * efds,struct timeval * ecore_timeout)164 _ecore_glib_select__locked(GMainContext *ctx,
165 int ecore_fds,
166 fd_set *rfds,
167 fd_set *wfds,
168 fd_set *efds,
169 struct timeval *ecore_timeout)
170 {
171 int priority, maxfds, glib_fds, reqfds, reqtimeout, ret;
172 struct timeval *timeout, glib_timeout;
173
174 g_main_context_prepare(ctx, &priority);
175 reqfds = _ecore_glib_context_query(ctx, priority, &reqtimeout);
176 if (reqfds < 0) goto error;
177
178 glib_fds = _ecore_glib_context_poll_from
179 (_ecore_glib_fds, reqfds, rfds, wfds, efds);
180
181 if (reqtimeout == -1)
182 timeout = ecore_timeout;
183 else
184 {
185 glib_timeout.tv_sec = reqtimeout / 1000;
186 glib_timeout.tv_usec = (reqtimeout % 1000) * 1000;
187
188 if (!ecore_timeout || timercmp(ecore_timeout, &glib_timeout, >))
189 timeout = &glib_timeout;
190 else
191 timeout = ecore_timeout;
192 }
193
194 maxfds = (ecore_fds >= glib_fds) ? ecore_fds : glib_fds;
195 ret = _ecore_glib_select_original(maxfds, rfds, wfds, efds, timeout);
196
197 ret = _ecore_glib_context_poll_to
198 (_ecore_glib_fds, reqfds, rfds, wfds, efds, ret);
199
200 if (g_main_context_check(ctx, priority, _ecore_glib_fds, reqfds))
201 g_main_context_dispatch(ctx);
202
203 return ret;
204
205 error:
206 return _ecore_glib_select_original
207 (ecore_fds, rfds, wfds, efds, ecore_timeout);
208 }
209
210 static int
_ecore_glib_select(int ecore_fds,fd_set * rfds,fd_set * wfds,fd_set * efds,struct timeval * ecore_timeout)211 _ecore_glib_select(int ecore_fds,
212 fd_set *rfds,
213 fd_set *wfds,
214 fd_set *efds,
215 struct timeval *ecore_timeout)
216 {
217 GMainContext *ctx;
218 int ret;
219
220 ctx = g_main_context_default();
221
222 while (!g_main_context_acquire(ctx))
223 g_thread_yield();
224
225 #if GLIB_CHECK_VERSION(2,32,0)
226 g_rec_mutex_lock(_ecore_glib_select_lock);
227 #else
228 g_static_rec_mutex_lock(_ecore_glib_select_lock);
229 #endif
230
231 ret = _ecore_glib_select__locked
232 (ctx, ecore_fds, rfds, wfds, efds, ecore_timeout);
233
234 #if GLIB_CHECK_VERSION(2,32,0)
235 g_rec_mutex_unlock(_ecore_glib_select_lock);
236 #else
237 g_static_rec_mutex_unlock(_ecore_glib_select_lock);
238 #endif
239 g_main_context_release(ctx);
240
241 return ret;
242 }
243
244 #endif
245
246 void
_ecore_glib_init(void)247 _ecore_glib_init(void)
248 {
249 #ifdef HAVE_GLIB
250 #if GLIB_CHECK_VERSION(2,32,0)
251 _ecore_glib_select_lock = malloc(sizeof(GRecMutex));
252 g_rec_mutex_init(_ecore_glib_select_lock);
253 #else
254 if (!g_thread_get_initialized()) g_thread_init(NULL);
255 _ecore_glib_select_lock = malloc(sizeof(GStaticRecMutex));
256 g_static_rec_mutex_init(_ecore_glib_select_lock);
257 #endif
258 #endif
259 }
260
261 void
_ecore_glib_shutdown(void)262 _ecore_glib_shutdown(void)
263 {
264 #ifdef HAVE_GLIB
265 if (!_ecore_glib_active) return;
266 _ecore_glib_active = EINA_FALSE;
267
268 if (ecore_main_loop_select_func_get() == _ecore_glib_select)
269 ecore_main_loop_select_func_set(_ecore_glib_select_original);
270
271 if (_ecore_glib_fds)
272 {
273 free(_ecore_glib_fds);
274 _ecore_glib_fds = NULL;
275 }
276 _ecore_glib_fds_size = 0;
277
278 #if GLIB_CHECK_VERSION(2,32,0)
279 g_rec_mutex_clear(_ecore_glib_select_lock);
280 free(_ecore_glib_select_lock);
281 _ecore_glib_select_lock = NULL;
282 #else
283 g_static_rec_mutex_free(_ecore_glib_select_lock);
284 _ecore_glib_select_lock = NULL;
285 #endif
286 #endif
287 }
288
289 EAPI Eina_Bool
ecore_main_loop_glib_integrate(void)290 ecore_main_loop_glib_integrate(void)
291 {
292 #ifdef HAVE_GLIB
293 void *func;
294
295 if (_ecore_glib_active) return EINA_TRUE;
296 func = ecore_main_loop_select_func_get();
297 if (func == _ecore_glib_select) return EINA_TRUE;
298 _ecore_glib_select_original = func;
299 ecore_main_loop_select_func_set(_ecore_glib_select);
300 _ecore_glib_active = EINA_TRUE;
301
302 /* Init only when requested */
303 _ecore_glib_init();
304 return EINA_TRUE;
305 #else
306 ERR("No glib support");
307 return EINA_FALSE;
308 #endif
309 }
310
311 Eina_Bool _ecore_glib_always_integrate = 1;
312
313 EAPI void
ecore_main_loop_glib_always_integrate_disable(void)314 ecore_main_loop_glib_always_integrate_disable(void)
315 {
316 _ecore_glib_always_integrate = 0;
317 }
318