diff options
author | Christian Grothoff <christian@grothoff.org> | 2011-08-15 09:18:27 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2011-08-15 09:18:27 +0000 |
commit | ee499cde2f179375c1f897564a16100052388cd3 (patch) | |
tree | 1eedc65143cb963a11477ce7da169b742d58e197 | |
parent | 9901656e38b2849d5588a585312984e3e84dbe73 (diff) | |
download | gnunet-gtk-ee499cde2f179375c1f897564a16100052388cd3.tar.gz gnunet-gtk-ee499cde2f179375c1f897564a16100052388cd3.zip |
LRN: scheduler compatible select on top of g_poll for improved W32 portability
-rw-r--r-- | src/gnunet-gtk.c | 667 |
1 files changed, 559 insertions, 108 deletions
diff --git a/src/gnunet-gtk.c b/src/gnunet-gtk.c index fc5916f0..0784432a 100644 --- a/src/gnunet-gtk.c +++ b/src/gnunet-gtk.c | |||
@@ -138,8 +138,551 @@ struct MainContext | |||
138 | */ | 138 | */ |
139 | gint max_priority; | 139 | gint max_priority; |
140 | 140 | ||
141 | #if WINDOWS | ||
142 | /** | ||
143 | * Array to hold pipe handles during a select() call | ||
144 | */ | ||
145 | struct GNUNET_DISK_FileHandle **read_array; | ||
146 | |||
147 | /** | ||
148 | * Allocated length of read_array | ||
149 | */ | ||
150 | int read_array_length; | ||
151 | |||
152 | /** | ||
153 | * Event to fire when a socket is ready for reading | ||
154 | */ | ||
155 | HANDLE hEventRead; | ||
156 | |||
157 | /** | ||
158 | * Event to fire when a socket is ready for writing | ||
159 | */ | ||
160 | HANDLE hEventWrite; | ||
161 | |||
162 | /** | ||
163 | * Event to fire when a socket had an error | ||
164 | */ | ||
165 | HANDLE hEventException; | ||
166 | |||
167 | /** | ||
168 | * Event that is permanently enabled and is used to signal a pipe | ||
169 | * that is ready for writing (asynchronous pipes are always writable) | ||
170 | */ | ||
171 | HANDLE hEventPipeWrite; | ||
172 | |||
173 | /** | ||
174 | * Event that is permanently enabled and is used to signal a pipe | ||
175 | * that is ready for reading (used to wake up early on a pipe that | ||
176 | * is known to be readable) | ||
177 | */ | ||
178 | HANDLE hEventReadReady; | ||
179 | |||
180 | /** | ||
181 | * A list to hold file handles that are ready for reading | ||
182 | */ | ||
183 | struct GNUNET_CONTAINER_SList *handles_read; | ||
184 | |||
185 | /** | ||
186 | * A list to hold file handles that are ready for writing | ||
187 | */ | ||
188 | struct GNUNET_CONTAINER_SList *handles_write; | ||
189 | |||
190 | /** | ||
191 | * A list to hold file handles that are broken | ||
192 | */ | ||
193 | struct GNUNET_CONTAINER_SList *handles_except; | ||
194 | #endif | ||
141 | }; | 195 | }; |
142 | 196 | ||
197 | static void | ||
198 | gnunet_gtk_dispatch_task (void *cls, | ||
199 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
200 | { | ||
201 | struct MainContext *mc = (struct MainContext *) cls; | ||
202 | g_main_context_dispatch (mc->gmc); | ||
203 | } | ||
204 | |||
205 | #ifndef FD_COPY | ||
206 | #define FD_COPY(s, d) (memcpy ((d), (s), sizeof (fd_set))) | ||
207 | #endif | ||
208 | |||
209 | int | ||
210 | gnunet_gtk_select (void *cls, | ||
211 | struct GNUNET_NETWORK_FDSet *rfds, | ||
212 | struct GNUNET_NETWORK_FDSet *wfds, | ||
213 | struct GNUNET_NETWORK_FDSet *efds, | ||
214 | const struct GNUNET_TIME_Relative timeout) | ||
215 | { | ||
216 | struct MainContext *mc = (struct MainContext *) cls; | ||
217 | int max_nfds; | ||
218 | gint poll_result; | ||
219 | |||
220 | GPollFD *gfds; | ||
221 | gint delay; | ||
222 | |||
223 | guint i; | ||
224 | guint fd_counter = 0; | ||
225 | |||
226 | guint allocated_nfds, need_gfds; | ||
227 | |||
228 | fd_set aread, awrite, aexcept; | ||
229 | |||
230 | #if WINDOWS | ||
231 | int always_ready_write_fd = -1; | ||
232 | int sock_read = 0, sock_write = 0, sock_err = 0, socks = 0; | ||
233 | |||
234 | int pre_ret = 0; | ||
235 | int select_ret = 0; | ||
236 | int result = 0; | ||
237 | |||
238 | int read_handles = 0; | ||
239 | DWORD waitstatus; | ||
240 | #endif | ||
241 | |||
242 | FD_ZERO (&aread); | ||
243 | FD_ZERO (&awrite); | ||
244 | FD_ZERO (&aexcept); | ||
245 | if (rfds) | ||
246 | FD_COPY (&rfds->sds, &aread); | ||
247 | if (wfds) | ||
248 | FD_COPY (&wfds->sds, &awrite); | ||
249 | if (efds) | ||
250 | FD_COPY (&efds->sds, &aexcept); | ||
251 | |||
252 | #if WINDOWS | ||
253 | ResetEvent (mc->hEventRead); | ||
254 | ResetEvent (mc->hEventWrite); | ||
255 | ResetEvent (mc->hEventException); | ||
256 | |||
257 | GNUNET_CONTAINER_slist_clear (mc->handles_read); | ||
258 | GNUNET_CONTAINER_slist_clear (mc->handles_write); | ||
259 | GNUNET_CONTAINER_slist_clear (mc->handles_except); | ||
260 | #endif | ||
261 | |||
262 | if (TRUE != g_main_loop_is_running (mc->gml)) | ||
263 | return GNUNET_NETWORK_socket_select (rfds, wfds, efds, timeout); | ||
264 | |||
265 | if (rfds != NULL) | ||
266 | max_nfds = rfds->nsds; | ||
267 | else | ||
268 | max_nfds = -1; | ||
269 | if (wfds != NULL && max_nfds < wfds->nsds) | ||
270 | max_nfds = wfds->nsds; | ||
271 | if (efds != NULL && max_nfds < efds->nsds) | ||
272 | max_nfds = efds->nsds; | ||
273 | |||
274 | allocated_nfds = mc->cached_poll_array_size; | ||
275 | gfds = mc->cached_poll_array; | ||
276 | if (allocated_nfds == 0) | ||
277 | { | ||
278 | /* TODO: get some statistics, find the maximum number of fds ever | ||
279 | * polled during normal gnunet-gtk operation, and set this to that number. | ||
280 | */ | ||
281 | mc->cached_poll_array = gfds = g_new (GPollFD, 30); | ||
282 | mc->cached_poll_array_size = allocated_nfds = 30; | ||
283 | } | ||
284 | |||
285 | while (1) | ||
286 | { | ||
287 | fd_counter = 0; | ||
288 | #if !WINDOWS | ||
289 | gboolean need_realloc = FALSE; | ||
290 | for (i = 0; !need_realloc && i < max_nfds; i += 1) | ||
291 | { | ||
292 | int isset[3]; | ||
293 | isset[0] = FD_ISSET (i, &rfds->sds); | ||
294 | isset[1] = FD_ISSET (i, &wfds->sds); | ||
295 | isset[2] = FD_ISSET (i, &efds->sds); | ||
296 | if (!isset[0] && !isset[1] && !isset[2]) | ||
297 | continue; | ||
298 | if (fd_counter >= allocated_nfds) | ||
299 | { | ||
300 | need_realloc = TRUE; | ||
301 | break; | ||
302 | } | ||
303 | gfds[fd_counter].fd = i; | ||
304 | gfds[fd_counter].events = (isset[0] ? G_IO_IN | G_IO_HUP | G_IO_ERR : 0) | ||
305 | | (isset[1] ? G_IO_OUT | G_IO_ERR : 0) | (issed[2] ? G_IO_ERR : 0); | ||
306 | fd_counter += 1; | ||
307 | } | ||
308 | if (need_realloc) | ||
309 | { | ||
310 | mc->cached_poll_array = fds = g_renew (GPollFD, fds, mc->cached_poll_array_size * 2); | ||
311 | mc->cached_poll_array_size = allocated_nfds = nfds; | ||
312 | fd_counter = 0; | ||
313 | need_realloc = FALSE; | ||
314 | } | ||
315 | else | ||
316 | break; | ||
317 | #else | ||
318 | struct GNUNET_CONTAINER_SList_Iterator *t; | ||
319 | /* We might overshoot a little, but that won't hurt very much */ | ||
320 | int need_nfds = (rfds->sds.fd_count + rfds->sds.fd_count + rfds->sds.fd_count > 0 ? 3 : 0) | ||
321 | + (rfds == NULL ? 0 : GNUNET_CONTAINER_slist_count (rfds->handles)) | ||
322 | + (wfds == NULL ? 0 : 1) | ||
323 | + 1; | ||
324 | if (need_nfds >= allocated_nfds) | ||
325 | { | ||
326 | /* Since there are also gmainloop's own fds, just need_nfds won't be | ||
327 | * enough, so make it twice as long. | ||
328 | */ | ||
329 | mc->cached_poll_array = gfds = g_renew (GPollFD, gfds, need_nfds * 2); | ||
330 | mc->cached_poll_array_size = allocated_nfds = need_nfds * 2; | ||
331 | } | ||
332 | if (mc->read_array_length < GNUNET_CONTAINER_slist_count (rfds->handles)) | ||
333 | { | ||
334 | mc->read_array = GNUNET_realloc (mc->read_array, GNUNET_CONTAINER_slist_count (rfds->handles) * sizeof (struct GNUNET_DISK_FileHandle *)); | ||
335 | mc->read_array_length = GNUNET_CONTAINER_slist_count (rfds->handles); | ||
336 | } | ||
337 | if (rfds != NULL) | ||
338 | { | ||
339 | for (t = GNUNET_CONTAINER_slist_begin (rfds->handles), i = 0; | ||
340 | GNUNET_CONTAINER_slist_end (t) != GNUNET_YES; | ||
341 | GNUNET_CONTAINER_slist_next (t), i += 1) | ||
342 | { | ||
343 | struct GNUNET_DISK_FileHandle *fh; | ||
344 | fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (t, NULL); | ||
345 | if (fh->type == GNUNET_PIPE) | ||
346 | { | ||
347 | if (!ReadFile (fh->h, NULL, 0, NULL, fh->oOverlapRead)) | ||
348 | { | ||
349 | DWORD error_code = GetLastError(); | ||
350 | if (error_code == ERROR_IO_PENDING) | ||
351 | { | ||
352 | #if DEBUG_NETWORK | ||
353 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding the pipe's 0x%x overlapped event to the array as %d\n", fh->h, nhandles); | ||
354 | #endif | ||
355 | gfds[fd_counter].fd = (intptr_t) fh->oOverlapRead->hEvent; | ||
356 | /* On W32 .events makes no sense - g_poll will just OR its | ||
357 | * contents into .revents when the .fd event fires. | ||
358 | * So we'll use it in the way that suits us the best. | ||
359 | */ | ||
360 | gfds[fd_counter].events = G_IO_IN; | ||
361 | fd_counter += 1; | ||
362 | mc->read_array[read_handles] = fh; | ||
363 | read_handles += 1; | ||
364 | } | ||
365 | else | ||
366 | { | ||
367 | gfds[fd_counter].fd = (intptr_t) mc->hEventReadReady; | ||
368 | gfds[fd_counter].events = G_IO_HUP; | ||
369 | fd_counter += 1; | ||
370 | mc->read_array[read_handles] = fh; | ||
371 | read_handles += 1; | ||
372 | } | ||
373 | } | ||
374 | else | ||
375 | { | ||
376 | #if DEBUG_NETWORK | ||
377 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding the read ready event to the array as %d\n", nhandles); | ||
378 | #endif | ||
379 | gfds[fd_counter].fd = (intptr_t) mc->hEventReadReady; | ||
380 | gfds[fd_counter].events = G_IO_IN; | ||
381 | fd_counter += 1; | ||
382 | mc->read_array[read_handles] = fh; | ||
383 | read_handles += 1; | ||
384 | } | ||
385 | } | ||
386 | else | ||
387 | { | ||
388 | GNUNET_CONTAINER_slist_add (mc->handles_read, | ||
389 | GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT, | ||
390 | fh, sizeof (struct GNUNET_DISK_FileHandle)); | ||
391 | pre_ret += 1; | ||
392 | } | ||
393 | } | ||
394 | } | ||
395 | if (wfds != NULL && GNUNET_CONTAINER_slist_count (wfds->handles) > 0) | ||
396 | { | ||
397 | gfds[fd_counter].fd = (intptr_t) mc->hEventPipeWrite; | ||
398 | gfds[fd_counter].events = G_IO_OUT; | ||
399 | always_ready_write_fd = fd_counter; | ||
400 | fd_counter += 1; | ||
401 | } | ||
402 | if (efds != NULL) | ||
403 | { | ||
404 | for (t = GNUNET_CONTAINER_slist_begin (efds->handles), i = 0; | ||
405 | GNUNET_CONTAINER_slist_end (t) != GNUNET_YES; | ||
406 | GNUNET_CONTAINER_slist_next (t), i += 1) | ||
407 | { | ||
408 | struct GNUNET_DISK_FileHandle *fh; | ||
409 | DWORD dwBytes; | ||
410 | fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (t, NULL); | ||
411 | if (fh->type == GNUNET_PIPE) | ||
412 | { | ||
413 | if (!PeekNamedPipe (fh->h, NULL, 0, NULL, &dwBytes, NULL)) | ||
414 | { | ||
415 | GNUNET_CONTAINER_slist_add (mc->handles_except, | ||
416 | GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT, | ||
417 | fh, sizeof (struct GNUNET_DISK_FileHandle)); | ||
418 | pre_ret += 1; | ||
419 | } | ||
420 | } | ||
421 | } | ||
422 | } | ||
423 | GNUNET_CONTAINER_slist_iter_destroy (t); | ||
424 | |||
425 | if (rfds != NULL && rfds->sds.fd_count > 0) | ||
426 | { | ||
427 | #if DEBUG_NETWORK | ||
428 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding the socket read event to the array as %d\n", fd_counter); | ||
429 | #endif | ||
430 | gfds[fd_counter].fd = (intptr_t) mc->hEventRead; | ||
431 | gfds[fd_counter].events = G_IO_IN; | ||
432 | for (i = 0; i < rfds->sds.fd_count; i++) | ||
433 | WSAEventSelect (rfds->sds.fd_array[i], mc->hEventRead, FD_ACCEPT | FD_READ | FD_CLOSE); | ||
434 | fd_counter += 1; | ||
435 | sock_read = rfds->sds.fd_count; | ||
436 | } | ||
437 | if (wfds != NULL && wfds->sds.fd_count > 0) | ||
438 | { | ||
439 | int wakeup = 0; | ||
440 | #if DEBUG_NETWORK | ||
441 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding the socket write event to the array as %d\n", fd_counter); | ||
442 | #endif | ||
443 | gfds[fd_counter].fd = (intptr_t) mc->hEventWrite; | ||
444 | gfds[fd_counter].events = G_IO_OUT; | ||
445 | for (i = 0; i < wfds->sds.fd_count; i++) | ||
446 | { | ||
447 | DWORD error; | ||
448 | int status; | ||
449 | status = send (wfds->sds.fd_array[i], NULL, 0, 0); | ||
450 | error = GetLastError (); | ||
451 | #if DEBUG_NETWORK | ||
452 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "pre-send to the socket %d returned %d (%u)\n", i, status, error); | ||
453 | #endif | ||
454 | if (status == 0 || (error != WSAEWOULDBLOCK && error != WSAENOTCONN)) | ||
455 | wakeup = 1; | ||
456 | WSAEventSelect (wfds->sds.fd_array[i], mc->hEventWrite, FD_WRITE | FD_CONNECT | FD_CLOSE); | ||
457 | } | ||
458 | if (wakeup) | ||
459 | SetEvent (mc->hEventWrite); | ||
460 | fd_counter += 1; | ||
461 | sock_write = wfds->sds.fd_count; | ||
462 | } | ||
463 | if (efds != NULL && efds->sds.fd_count > 0) | ||
464 | { | ||
465 | #if DEBUG_NETWORK | ||
466 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding the socket error event to the array as %d\n", fd_counter); | ||
467 | #endif | ||
468 | gfds[fd_counter].fd = (intptr_t) mc->hEventException; | ||
469 | gfds[fd_counter].events = G_IO_ERR; | ||
470 | for (i = 0; i < efds->sds.fd_count; i++) | ||
471 | WSAEventSelect (efds->sds.fd_array[i], mc->hEventException, FD_OOB | FD_CLOSE); | ||
472 | fd_counter += 1; | ||
473 | sock_err = efds->sds.fd_count; | ||
474 | } | ||
475 | break; | ||
476 | } | ||
477 | socks = sock_read + sock_write + sock_err; | ||
478 | #endif | ||
479 | |||
480 | g_main_context_prepare (mc->gmc, &mc->max_priority); | ||
481 | while (allocated_nfds < (need_gfds = g_main_context_query (mc->gmc, | ||
482 | mc->max_priority, &delay, &gfds[fd_counter], allocated_nfds - fd_counter))) | ||
483 | { | ||
484 | mc->cached_poll_array = gfds = g_renew (GPollFD, gfds, allocated_nfds - fd_counter + need_gfds); | ||
485 | mc->cached_poll_array_size = allocated_nfds = allocated_nfds - fd_counter + need_gfds; | ||
486 | } | ||
487 | mc->poll_array_active = fd_counter + need_gfds; | ||
488 | |||
489 | if (timeout.rel_value != GNUNET_TIME_UNIT_FOREVER_REL.rel_value) | ||
490 | { | ||
491 | if (delay >= 0) | ||
492 | delay = MIN(timeout.rel_value / GNUNET_TIME_UNIT_MILLISECONDS.rel_value, delay); | ||
493 | else | ||
494 | delay = timeout.rel_value / GNUNET_TIME_UNIT_MILLISECONDS.rel_value; | ||
495 | } | ||
496 | |||
497 | if (pre_ret > 0) | ||
498 | { | ||
499 | #if DEBUG_NETWORK | ||
500 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "pre_ret is %d, setting delay to 0\n", pre_ret); | ||
501 | #endif | ||
502 | delay = 0; | ||
503 | } | ||
504 | |||
505 | #if DEBUG_NETWORK | ||
506 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "We have %d of our FDs and %d of GMC ones, going to wait %6dms\n", fd_counter, need_gfds, delay); | ||
507 | #endif | ||
508 | |||
509 | poll_result = g_poll (gfds, fd_counter + need_gfds, delay); | ||
510 | |||
511 | #if DEBUG_NETWORK | ||
512 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "g_poll returned : %d\n", poll_result); | ||
513 | #endif | ||
514 | |||
515 | /* Take care of GUI events. | ||
516 | * Dispatching the events here will eventually crash the scheduler, must do this | ||
517 | * from within a task (currently we're not in a task, but in a select() call, remember) | ||
518 | * Startup reason is used to pass the scheduler sanity check. | ||
519 | */ | ||
520 | if (TRUE == g_main_context_check (mc->gmc, mc->max_priority, &gfds[fd_counter], need_gfds)) | ||
521 | GNUNET_SCHEDULER_add_continuation (gnunet_gtk_dispatch_task, mc, GNUNET_SCHEDULER_REASON_STARTUP); | ||
522 | |||
523 | #if !WINDOWS | ||
524 | if (rfds) | ||
525 | FD_ZERO (rfds); | ||
526 | if (wfds) | ||
527 | FD_ZERO (wfds); | ||
528 | if (efds) | ||
529 | FD_ZERO (efds); | ||
530 | for (i = 0; i < fd_counter; i++) | ||
531 | { | ||
532 | int set[3]; | ||
533 | if (set[0] = FD_ISSET (gfds[i].fd, &aread)) | ||
534 | FD_SET (gfds[i].fd, rfds->sds); | ||
535 | if (set[1] = FD_ISSET (gfds[i].fd, &awrite)) | ||
536 | FD_SET (gfds[i].fd, wfds->sds); | ||
537 | if (set[2] = FD_ISSET (gfds[i].fd, &aexcept)) | ||
538 | FD_SET (gfds[i].fd, efds->sds); | ||
539 | if (set[0] || set[1] || set[2]) | ||
540 | result += 1; | ||
541 | } | ||
542 | #else | ||
543 | if (socks > 0) | ||
544 | { | ||
545 | struct timeval tvslice; | ||
546 | tvslice.tv_sec = 0; | ||
547 | tvslice.tv_usec = 0; | ||
548 | select_ret = select (max_nfds, &aread, &awrite, &aexcept, &tvslice); | ||
549 | if (select_ret == -1) | ||
550 | select_ret = 0; | ||
551 | #if DEBUG_NETWORK | ||
552 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "select() returned %d\n", select_ret); | ||
553 | #endif | ||
554 | } | ||
555 | if (always_ready_write_fd >= 0 && gfds[always_ready_write_fd].revents & G_IO_OUT) | ||
556 | { | ||
557 | GNUNET_CONTAINER_slist_append (mc->handles_write, wfds->handles); | ||
558 | result += GNUNET_CONTAINER_slist_count (mc->handles_write); | ||
559 | #if DEBUG_NETWORK | ||
560 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Added write pipe\n"); | ||
561 | #endif | ||
562 | } | ||
563 | for (i = 0; i < read_handles; i++) | ||
564 | { | ||
565 | DWORD error; | ||
566 | BOOL bret; | ||
567 | if (!(gfds[i].revents & (G_IO_IN | G_IO_HUP | G_IO_ERR))) | ||
568 | continue; | ||
569 | SetLastError (0); | ||
570 | waitstatus = 0; | ||
571 | bret = PeekNamedPipe (mc->read_array[i]->h, NULL, 0, NULL, &waitstatus, NULL); | ||
572 | error = GetLastError (); | ||
573 | #if DEBUG_NETWORK | ||
574 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peek at read pipe %d (0x%x) returned %d (%d bytes available) GLE %u\n", i, mc->read_array[i]->h, bret, waitstatus, error); | ||
575 | #endif | ||
576 | if (bret == 0 || (gfds[i].revents & G_IO_ERR)) | ||
577 | { | ||
578 | if (efds != NULL) | ||
579 | { | ||
580 | struct GNUNET_CONTAINER_SList_Iterator *t; | ||
581 | for (t = GNUNET_CONTAINER_slist_begin (efds->handles), i = 0; | ||
582 | GNUNET_CONTAINER_slist_end (t) != GNUNET_YES; | ||
583 | GNUNET_CONTAINER_slist_next (t), i += 1) | ||
584 | { | ||
585 | struct GNUNET_DISK_FileHandle *fh; | ||
586 | fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (t, NULL); | ||
587 | if (fh == mc->read_array[i]) | ||
588 | { | ||
589 | GNUNET_CONTAINER_slist_add (mc->handles_except, | ||
590 | GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT, | ||
591 | fh, sizeof (struct GNUNET_DISK_FileHandle)); | ||
592 | break; | ||
593 | } | ||
594 | } | ||
595 | GNUNET_CONTAINER_slist_iter_destroy (t); | ||
596 | } | ||
597 | } | ||
598 | else if (waitstatus <= 0) | ||
599 | continue; | ||
600 | GNUNET_CONTAINER_slist_add (mc->handles_read, | ||
601 | GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT, | ||
602 | mc->read_array[i], sizeof (struct GNUNET_DISK_FileHandle)); | ||
603 | result += 1; | ||
604 | #if DEBUG_NETWORK | ||
605 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Added read Pipe 0x%x (0x%x)\n", mc->read_array[i], mc->read_array[i]->h); | ||
606 | #endif | ||
607 | } | ||
608 | waitstatus = WaitForSingleObject (mc->hEventWrite, 0); | ||
609 | #if DEBUG_NETWORK | ||
610 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Wait for the write event returned %d\n", waitstatus); | ||
611 | #endif | ||
612 | if (waitstatus == WAIT_OBJECT_0) | ||
613 | { | ||
614 | for (i = 0; i < wfds->sds.fd_count; i++) | ||
615 | { | ||
616 | DWORD error; | ||
617 | int status; | ||
618 | int so_error = 0; | ||
619 | int sizeof_so_error = sizeof (so_error); | ||
620 | int gso_result = getsockopt (wfds->sds.fd_array[i], SOL_SOCKET, SO_ERROR, (char *) &so_error, &sizeof_so_error); | ||
621 | status = send (wfds->sds.fd_array[i], NULL, 0, 0); | ||
622 | error = GetLastError (); | ||
623 | #if DEBUG_NETWORK | ||
624 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "send to the socket %d returned %d (%u)\n", i, status, error); | ||
625 | #endif | ||
626 | if (status == 0 | ||
627 | || (error != WSAEWOULDBLOCK && error != WSAENOTCONN) | ||
628 | || (status == -1 && gso_result == 0 && error == WSAENOTCONN && so_error == WSAECONNREFUSED)) | ||
629 | { | ||
630 | FD_SET (wfds->sds.fd_array[i], &awrite); | ||
631 | result += 1; | ||
632 | } | ||
633 | } | ||
634 | } | ||
635 | if (rfds) | ||
636 | { | ||
637 | struct GNUNET_CONTAINER_SList_Iterator *t; | ||
638 | for (i = 0; i < rfds->sds.fd_count; i++) | ||
639 | WSAEventSelect (rfds->sds.fd_array[i], mc->hEventRead, 0); | ||
640 | for (t = GNUNET_CONTAINER_slist_begin (rfds->handles); | ||
641 | GNUNET_CONTAINER_slist_end (t) != GNUNET_YES; | ||
642 | GNUNET_CONTAINER_slist_next (t)) | ||
643 | { | ||
644 | struct GNUNET_DISK_FileHandle *fh; | ||
645 | fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (t, NULL); | ||
646 | if (fh->type == GNUNET_PIPE) | ||
647 | CancelIo (fh->h); | ||
648 | } | ||
649 | GNUNET_CONTAINER_slist_iter_destroy (t); | ||
650 | GNUNET_NETWORK_fdset_zero (rfds); | ||
651 | if (select_ret != -1 && socks > 0) | ||
652 | GNUNET_NETWORK_fdset_copy_native (rfds, &aread, select_ret); | ||
653 | GNUNET_CONTAINER_slist_append (rfds->handles, mc->handles_read); | ||
654 | } | ||
655 | if (wfds) | ||
656 | { | ||
657 | for (i = 0; i < wfds->sds.fd_count; i++) | ||
658 | WSAEventSelect (wfds->sds.fd_array[i], mc->hEventWrite, 0); | ||
659 | GNUNET_NETWORK_fdset_zero (wfds); | ||
660 | if (select_ret != -1 && socks > 0) | ||
661 | GNUNET_NETWORK_fdset_copy_native (wfds, &awrite, select_ret); | ||
662 | GNUNET_CONTAINER_slist_append (wfds->handles, mc->handles_write); | ||
663 | } | ||
664 | if (efds) | ||
665 | { | ||
666 | for (i = 0; i < efds->sds.fd_count; i++) | ||
667 | WSAEventSelect (efds->sds.fd_array[i], mc->hEventException, 0); | ||
668 | GNUNET_NETWORK_fdset_zero (efds); | ||
669 | if (select_ret != -1 && socks > 0) | ||
670 | GNUNET_NETWORK_fdset_copy_native (efds, &aexcept, select_ret); | ||
671 | GNUNET_CONTAINER_slist_append (efds->handles, mc->handles_except); | ||
672 | result += GNUNET_CONTAINER_slist_count (mc->handles_except); | ||
673 | } | ||
674 | if (fd_counter > 0) | ||
675 | /* This is not accurate (select_ret counts write-ready sockets, | ||
676 | * and result does as well. Anything out there actually cares | ||
677 | * about this? | ||
678 | */ | ||
679 | return select_ret + result; | ||
680 | else | ||
681 | return 0; | ||
682 | #endif | ||
683 | return result; | ||
684 | } | ||
685 | |||
143 | 686 | ||
144 | /** | 687 | /** |
145 | * Get the name of the directory where all of our package | 688 | * Get the name of the directory where all of our package |
@@ -178,112 +721,6 @@ free_context (struct MainContext *context) | |||
178 | GNUNET_free (context); | 721 | GNUNET_free (context); |
179 | } | 722 | } |
180 | 723 | ||
181 | |||
182 | /** | ||
183 | * Run GTK tasks that are ready. | ||
184 | * | ||
185 | * @param cls the 'struct MainContext' | ||
186 | * @param tc task context | ||
187 | */ | ||
188 | static void | ||
189 | run_ready (void *cls, | ||
190 | const struct GNUNET_SCHEDULER_TaskContext *tc); | ||
191 | |||
192 | |||
193 | /** | ||
194 | * Schedule the main GTK Event loop with the GNUnet scheduler. | ||
195 | * | ||
196 | * @param cls the 'struct MainContext' | ||
197 | * @param tc task context | ||
198 | */ | ||
199 | static void | ||
200 | schedule_main_loop (void *cls, | ||
201 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
202 | { | ||
203 | struct MainContext *mc = cls; | ||
204 | struct GNUNET_TIME_Relative delay; | ||
205 | gint timeout; | ||
206 | gint nfds; | ||
207 | GPollFD *fds; | ||
208 | guint allocated_nfds; | ||
209 | |||
210 | if ( (tc != NULL) && | ||
211 | (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason)) ) | ||
212 | { | ||
213 | g_main_loop_quit (mc->gml); | ||
214 | GNUNET_SCHEDULER_add_now (&schedule_main_loop, | ||
215 | mc); | ||
216 | return; | ||
217 | } | ||
218 | if (TRUE != g_main_loop_is_running (mc->gml)) | ||
219 | return; | ||
220 | g_main_context_prepare (mc->gmc, &mc->max_priority); | ||
221 | allocated_nfds = mc->cached_poll_array_size; | ||
222 | fds = mc->cached_poll_array; | ||
223 | while ((nfds = g_main_context_query (mc->gmc, mc->max_priority, | ||
224 | &timeout, fds, | ||
225 | allocated_nfds)) > allocated_nfds) | ||
226 | { | ||
227 | g_free (fds); | ||
228 | mc->cached_poll_array_size = allocated_nfds = nfds; | ||
229 | mc->cached_poll_array = fds = g_new (GPollFD, nfds); | ||
230 | } | ||
231 | mc->poll_array_active = nfds; | ||
232 | delay.rel_value = (uint64_t) timeout; | ||
233 | GNUNET_NETWORK_fdset_zero (mc->rs); | ||
234 | GNUNET_NETWORK_fdset_zero (mc->ws); | ||
235 | while (nfds > 0) | ||
236 | { | ||
237 | nfds--; | ||
238 | #ifdef __MINGW32__ | ||
239 | /* TODO: maybe #ifdef WINDOWS? -ndurner */ | ||
240 | if (fds[nfds].events & (G_IO_IN | G_IO_HUP | G_IO_ERR)) | ||
241 | GNUNET_NETWORK_fdset_set_native_w32_handle (mc->rs, (HANDLE) fds[nfds].fd); | ||
242 | if (fds[nfds].events & (G_IO_OUT | G_IO_ERR)) | ||
243 | GNUNET_NETWORK_fdset_set_native_w32_handle (mc->ws, (HANDLE) fds[nfds].fd); | ||
244 | #else | ||
245 | if (fds[nfds].events & (G_IO_IN | G_IO_HUP | G_IO_ERR)) | ||
246 | GNUNET_NETWORK_fdset_set_native (mc->rs, fds[nfds].fd); | ||
247 | if (fds[nfds].events & (G_IO_OUT | G_IO_ERR)) | ||
248 | GNUNET_NETWORK_fdset_set_native (mc->ws, fds[nfds].fd); | ||
249 | #endif | ||
250 | } | ||
251 | GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_UI, | ||
252 | GNUNET_SCHEDULER_NO_TASK, | ||
253 | delay, | ||
254 | mc->rs, | ||
255 | mc->ws, | ||
256 | &run_ready, | ||
257 | mc); | ||
258 | } | ||
259 | |||
260 | |||
261 | /** | ||
262 | * Run GTK tasks that are ready. | ||
263 | * | ||
264 | * @param cls the 'struct MainContext' | ||
265 | * @param tc task context | ||
266 | */ | ||
267 | static void | ||
268 | run_ready (void *cls, | ||
269 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
270 | { | ||
271 | struct MainContext *mc = cls; | ||
272 | |||
273 | g_poll (mc->cached_poll_array, | ||
274 | mc->poll_array_active, | ||
275 | 0); | ||
276 | if (TRUE == | ||
277 | g_main_context_check (mc->gmc, | ||
278 | mc->max_priority, | ||
279 | mc->cached_poll_array, | ||
280 | mc->poll_array_active)) | ||
281 | g_main_context_dispatch (mc->gmc); | ||
282 | GNUNET_SCHEDULER_add_now (&schedule_main_loop, | ||
283 | mc); | ||
284 | } | ||
285 | |||
286 | |||
287 | /** | 724 | /** |
288 | * Main context (global so we can free it on exit and use | 725 | * Main context (global so we can free it on exit and use |
289 | * it for termination). | 726 | * it for termination). |
@@ -562,6 +999,21 @@ run (void *cls, | |||
562 | if (mc->builder == NULL) | 999 | if (mc->builder == NULL) |
563 | return; | 1000 | return; |
564 | 1001 | ||
1002 | #if WINDOWS | ||
1003 | mc->hEventRead = CreateEvent (NULL, TRUE, FALSE, NULL); | ||
1004 | mc->hEventReadReady = CreateEvent (NULL, TRUE, TRUE, NULL); | ||
1005 | mc->hEventWrite = CreateEvent (NULL, TRUE, FALSE, NULL); | ||
1006 | mc->hEventException = CreateEvent (NULL, TRUE, FALSE, NULL); | ||
1007 | |||
1008 | mc->hEventPipeWrite = CreateEvent (NULL, TRUE, TRUE, NULL); | ||
1009 | |||
1010 | mc->handles_read = GNUNET_CONTAINER_slist_create (); | ||
1011 | mc->handles_write = GNUNET_CONTAINER_slist_create (); | ||
1012 | mc->handles_except = GNUNET_CONTAINER_slist_create (); | ||
1013 | mc->read_array = NULL; | ||
1014 | mc->read_array_length = 0; | ||
1015 | #endif | ||
1016 | |||
565 | /* setup tray icon */ | 1017 | /* setup tray icon */ |
566 | tray_icon = create_tray_icon(); | 1018 | tray_icon = create_tray_icon(); |
567 | 1019 | ||
@@ -618,7 +1070,7 @@ run (void *cls, | |||
618 | } | 1070 | } |
619 | /* start the event loop */ | 1071 | /* start the event loop */ |
620 | GNUNET_assert (TRUE == g_main_context_acquire (mc->gmc)); | 1072 | GNUNET_assert (TRUE == g_main_context_acquire (mc->gmc)); |
621 | schedule_main_loop (mc, NULL); | 1073 | GNUNET_SCHEDULER_set_select (gnunet_gtk_select, mc); |
622 | } | 1074 | } |
623 | 1075 | ||
624 | 1076 | ||
@@ -634,7 +1086,6 @@ GNUNET_GTK_get_main_window_object (const char *name) | |||
634 | return gtk_builder_get_object (mc->builder, name); | 1086 | return gtk_builder_get_object (mc->builder, name); |
635 | } | 1087 | } |
636 | 1088 | ||
637 | |||
638 | int | 1089 | int |
639 | main (int argc, char *const *argv) | 1090 | main (int argc, char *const *argv) |
640 | { | 1091 | { |