|
D-Bus
1.5.8
|
00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ 00002 /* dbus-mainloop.c Main loop utility 00003 * 00004 * Copyright (C) 2003, 2004 Red Hat, Inc. 00005 * 00006 * Licensed under the Academic Free License version 2.1 00007 * 00008 * This program is free software; you can redistribute it and/or modify 00009 * it under the terms of the GNU General Public License as published by 00010 * the Free Software Foundation; either version 2 of the License, or 00011 * (at your option) any later version. 00012 * 00013 * This program is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 * GNU General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU General Public License 00019 * along with this program; if not, write to the Free Software 00020 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00021 * 00022 */ 00023 00024 #include <config.h> 00025 #include "dbus-mainloop.h" 00026 00027 #ifndef DOXYGEN_SHOULD_SKIP_THIS 00028 00029 #include <dbus/dbus-hash.h> 00030 #include <dbus/dbus-list.h> 00031 #include <dbus/dbus-sysdeps.h> 00032 #include <dbus/dbus-watch.h> 00033 00034 #define MAINLOOP_SPEW 0 00035 00036 #if MAINLOOP_SPEW 00037 #ifdef DBUS_ENABLE_VERBOSE_MODE 00038 static const char* 00039 watch_flags_to_string (int flags) 00040 { 00041 const char *watch_type; 00042 00043 if ((flags & DBUS_WATCH_READABLE) && 00044 (flags & DBUS_WATCH_WRITABLE)) 00045 watch_type = "readwrite"; 00046 else if (flags & DBUS_WATCH_READABLE) 00047 watch_type = "read"; 00048 else if (flags & DBUS_WATCH_WRITABLE) 00049 watch_type = "write"; 00050 else 00051 watch_type = "not read or write"; 00052 return watch_type; 00053 } 00054 #endif /* DBUS_ENABLE_VERBOSE_MODE */ 00055 #endif /* MAINLOOP_SPEW */ 00056 00057 struct DBusLoop 00058 { 00059 int refcount; 00061 DBusHashTable *watches; 00062 DBusList *timeouts; 00063 int callback_list_serial; 00064 int watch_count; 00065 int timeout_count; 00066 int depth; 00067 DBusList *need_dispatch; 00068 }; 00069 00070 static short 00071 watch_flags_to_poll_events (unsigned int flags) 00072 { 00073 short events = 0; 00074 00075 if (flags & DBUS_WATCH_READABLE) 00076 events |= _DBUS_POLLIN; 00077 if (flags & DBUS_WATCH_WRITABLE) 00078 events |= _DBUS_POLLOUT; 00079 00080 return events; 00081 } 00082 00083 static unsigned int 00084 watch_flags_from_poll_revents (short revents) 00085 { 00086 unsigned int condition = 0; 00087 00088 if (revents & _DBUS_POLLIN) 00089 condition |= DBUS_WATCH_READABLE; 00090 if (revents & _DBUS_POLLOUT) 00091 condition |= DBUS_WATCH_WRITABLE; 00092 if (revents & _DBUS_POLLHUP) 00093 condition |= DBUS_WATCH_HANGUP; 00094 if (revents & _DBUS_POLLERR) 00095 condition |= DBUS_WATCH_ERROR; 00096 00097 return condition; 00098 } 00099 00100 typedef struct 00101 { 00102 DBusTimeout *timeout; 00103 unsigned long last_tv_sec; 00104 unsigned long last_tv_usec; 00105 } TimeoutCallback; 00106 00107 #define TIMEOUT_CALLBACK(callback) ((TimeoutCallback*)callback) 00108 00109 static TimeoutCallback* 00110 timeout_callback_new (DBusTimeout *timeout) 00111 { 00112 TimeoutCallback *cb; 00113 00114 cb = dbus_new (TimeoutCallback, 1); 00115 if (cb == NULL) 00116 return NULL; 00117 00118 cb->timeout = timeout; 00119 _dbus_get_current_time (&cb->last_tv_sec, 00120 &cb->last_tv_usec); 00121 return cb; 00122 } 00123 00124 static void 00125 timeout_callback_free (TimeoutCallback *cb) 00126 { 00127 dbus_free (cb); 00128 } 00129 00130 static void 00131 free_watch_table_entry (void *data) 00132 { 00133 DBusList **watches = data; 00134 DBusWatch *watch; 00135 00136 /* DBusHashTable sometimes calls free_function(NULL) even if you never 00137 * have NULL as a value */ 00138 if (watches == NULL) 00139 return; 00140 00141 for (watch = _dbus_list_pop_first (watches); 00142 watch != NULL; 00143 watch = _dbus_list_pop_first (watches)) 00144 { 00145 _dbus_watch_unref (watch); 00146 } 00147 00148 _dbus_assert (*watches == NULL); 00149 dbus_free (watches); 00150 } 00151 00152 DBusLoop* 00153 _dbus_loop_new (void) 00154 { 00155 DBusLoop *loop; 00156 00157 loop = dbus_new0 (DBusLoop, 1); 00158 if (loop == NULL) 00159 return NULL; 00160 00161 loop->watches = _dbus_hash_table_new (DBUS_HASH_INT, NULL, 00162 free_watch_table_entry); 00163 00164 if (loop->watches == NULL) 00165 { 00166 dbus_free (loop); 00167 return NULL; 00168 } 00169 00170 loop->refcount = 1; 00171 00172 return loop; 00173 } 00174 00175 DBusLoop * 00176 _dbus_loop_ref (DBusLoop *loop) 00177 { 00178 _dbus_assert (loop != NULL); 00179 _dbus_assert (loop->refcount > 0); 00180 00181 loop->refcount += 1; 00182 00183 return loop; 00184 } 00185 00186 void 00187 _dbus_loop_unref (DBusLoop *loop) 00188 { 00189 _dbus_assert (loop != NULL); 00190 _dbus_assert (loop->refcount > 0); 00191 00192 loop->refcount -= 1; 00193 if (loop->refcount == 0) 00194 { 00195 while (loop->need_dispatch) 00196 { 00197 DBusConnection *connection = _dbus_list_pop_first (&loop->need_dispatch); 00198 00199 dbus_connection_unref (connection); 00200 } 00201 00202 _dbus_hash_table_unref (loop->watches); 00203 dbus_free (loop); 00204 } 00205 } 00206 00207 static DBusList ** 00208 ensure_watch_table_entry (DBusLoop *loop, 00209 int fd) 00210 { 00211 DBusList **watches; 00212 00213 watches = _dbus_hash_table_lookup_int (loop->watches, fd); 00214 00215 if (watches == NULL) 00216 { 00217 watches = dbus_new0 (DBusList *, 1); 00218 00219 if (watches == NULL) 00220 return watches; 00221 00222 if (!_dbus_hash_table_insert_int (loop->watches, fd, watches)) 00223 { 00224 dbus_free (watches); 00225 watches = NULL; 00226 } 00227 } 00228 00229 return watches; 00230 } 00231 00232 static void 00233 cull_watches_for_invalid_fd (DBusLoop *loop, 00234 int fd) 00235 { 00236 DBusList *link; 00237 DBusList **watches; 00238 00239 _dbus_warn ("invalid request, socket fd %d not open\n", fd); 00240 watches = _dbus_hash_table_lookup_int (loop->watches, fd); 00241 00242 if (watches != NULL) 00243 { 00244 for (link = _dbus_list_get_first_link (watches); 00245 link != NULL; 00246 link = _dbus_list_get_next_link (watches, link)) 00247 _dbus_watch_invalidate (link->data); 00248 } 00249 00250 _dbus_hash_table_remove_int (loop->watches, fd); 00251 } 00252 00253 static void 00254 gc_watch_table_entry (DBusLoop *loop, 00255 DBusList **watches, 00256 int fd) 00257 { 00258 /* If watches is already NULL we have nothing to do */ 00259 if (watches == NULL) 00260 return; 00261 00262 /* We can't GC hash table entries if they're non-empty lists */ 00263 if (*watches != NULL) 00264 return; 00265 00266 _dbus_hash_table_remove_int (loop->watches, fd); 00267 } 00268 00269 dbus_bool_t 00270 _dbus_loop_add_watch (DBusLoop *loop, 00271 DBusWatch *watch) 00272 { 00273 int fd; 00274 DBusList **watches; 00275 00276 fd = dbus_watch_get_socket (watch); 00277 _dbus_assert (fd != -1); 00278 00279 watches = ensure_watch_table_entry (loop, fd); 00280 00281 if (watches == NULL) 00282 return FALSE; 00283 00284 if (_dbus_list_append (watches, _dbus_watch_ref (watch))) 00285 { 00286 loop->callback_list_serial += 1; 00287 loop->watch_count += 1; 00288 } 00289 else 00290 { 00291 _dbus_watch_unref (watch); 00292 gc_watch_table_entry (loop, watches, fd); 00293 00294 return FALSE; 00295 } 00296 00297 return TRUE; 00298 } 00299 00300 void 00301 _dbus_loop_remove_watch (DBusLoop *loop, 00302 DBusWatch *watch) 00303 { 00304 DBusList **watches; 00305 DBusList *link; 00306 int fd; 00307 00308 /* This relies on people removing watches before they invalidate them, 00309 * which has been safe since fd.o #33336 was fixed. Assert about it 00310 * so we don't regress. */ 00311 fd = dbus_watch_get_socket (watch); 00312 _dbus_assert (fd != -1); 00313 00314 watches = _dbus_hash_table_lookup_int (loop->watches, fd); 00315 00316 if (watches != NULL) 00317 { 00318 link = _dbus_list_get_first_link (watches); 00319 while (link != NULL) 00320 { 00321 DBusList *next = _dbus_list_get_next_link (watches, link); 00322 DBusWatch *this = link->data; 00323 00324 if (this == watch) 00325 { 00326 _dbus_list_remove_link (watches, link); 00327 loop->callback_list_serial += 1; 00328 loop->watch_count -= 1; 00329 _dbus_watch_unref (this); 00330 00331 /* if that was the last watch for that fd, drop the hash table 00332 * entry too */ 00333 gc_watch_table_entry (loop, watches, fd); 00334 00335 return; 00336 } 00337 00338 link = next; 00339 } 00340 } 00341 00342 _dbus_warn ("could not find watch %p to remove\n", watch); 00343 } 00344 00345 dbus_bool_t 00346 _dbus_loop_add_timeout (DBusLoop *loop, 00347 DBusTimeout *timeout) 00348 { 00349 TimeoutCallback *tcb; 00350 00351 tcb = timeout_callback_new (timeout); 00352 if (tcb == NULL) 00353 return FALSE; 00354 00355 if (_dbus_list_append (&loop->timeouts, tcb)) 00356 { 00357 loop->callback_list_serial += 1; 00358 loop->timeout_count += 1; 00359 } 00360 else 00361 { 00362 timeout_callback_free (tcb); 00363 return FALSE; 00364 } 00365 00366 return TRUE; 00367 } 00368 00369 void 00370 _dbus_loop_remove_timeout (DBusLoop *loop, 00371 DBusTimeout *timeout) 00372 { 00373 DBusList *link; 00374 00375 link = _dbus_list_get_first_link (&loop->timeouts); 00376 while (link != NULL) 00377 { 00378 DBusList *next = _dbus_list_get_next_link (&loop->timeouts, link); 00379 TimeoutCallback *this = link->data; 00380 00381 if (this->timeout == timeout) 00382 { 00383 _dbus_list_remove_link (&loop->timeouts, link); 00384 loop->callback_list_serial += 1; 00385 loop->timeout_count -= 1; 00386 timeout_callback_free (this); 00387 00388 return; 00389 } 00390 00391 link = next; 00392 } 00393 00394 _dbus_warn ("could not find timeout %p to remove\n", timeout); 00395 } 00396 00397 /* Convolutions from GLib, there really must be a better way 00398 * to do this. 00399 */ 00400 static dbus_bool_t 00401 check_timeout (unsigned long tv_sec, 00402 unsigned long tv_usec, 00403 TimeoutCallback *tcb, 00404 int *timeout) 00405 { 00406 long sec_remaining; 00407 long msec_remaining; 00408 unsigned long expiration_tv_sec; 00409 unsigned long expiration_tv_usec; 00410 long interval_seconds; 00411 long interval_milliseconds; 00412 int interval; 00413 00414 /* I'm pretty sure this function could suck (a lot) less */ 00415 00416 interval = dbus_timeout_get_interval (tcb->timeout); 00417 00418 interval_seconds = interval / 1000L; 00419 interval_milliseconds = interval % 1000L; 00420 00421 expiration_tv_sec = tcb->last_tv_sec + interval_seconds; 00422 expiration_tv_usec = tcb->last_tv_usec + interval_milliseconds * 1000; 00423 if (expiration_tv_usec >= 1000000) 00424 { 00425 expiration_tv_usec -= 1000000; 00426 expiration_tv_sec += 1; 00427 } 00428 00429 sec_remaining = expiration_tv_sec - tv_sec; 00430 /* need to force this to be signed, as it is intended to sometimes 00431 * produce a negative result 00432 */ 00433 msec_remaining = ((long) expiration_tv_usec - (long) tv_usec) / 1000L; 00434 00435 #if MAINLOOP_SPEW 00436 _dbus_verbose ("Interval is %ld seconds %ld msecs\n", 00437 interval_seconds, 00438 interval_milliseconds); 00439 _dbus_verbose ("Now is %lu seconds %lu usecs\n", 00440 tv_sec, tv_usec); 00441 _dbus_verbose ("Last is %lu seconds %lu usecs\n", 00442 tcb->last_tv_sec, tcb->last_tv_usec); 00443 _dbus_verbose ("Exp is %lu seconds %lu usecs\n", 00444 expiration_tv_sec, expiration_tv_usec); 00445 _dbus_verbose ("Pre-correction, sec_remaining %ld msec_remaining %ld\n", 00446 sec_remaining, msec_remaining); 00447 #endif 00448 00449 /* We do the following in a rather convoluted fashion to deal with 00450 * the fact that we don't have an integral type big enough to hold 00451 * the difference of two timevals in milliseconds. 00452 */ 00453 if (sec_remaining < 0 || (sec_remaining == 0 && msec_remaining < 0)) 00454 { 00455 *timeout = 0; 00456 } 00457 else 00458 { 00459 if (msec_remaining < 0) 00460 { 00461 msec_remaining += 1000; 00462 sec_remaining -= 1; 00463 } 00464 00465 if (sec_remaining > (_DBUS_INT_MAX / 1000) || 00466 msec_remaining > _DBUS_INT_MAX) 00467 *timeout = _DBUS_INT_MAX; 00468 else 00469 *timeout = sec_remaining * 1000 + msec_remaining; 00470 } 00471 00472 if (*timeout > interval) 00473 { 00474 /* This indicates that the system clock probably moved backward */ 00475 _dbus_verbose ("System clock set backward! Resetting timeout.\n"); 00476 00477 tcb->last_tv_sec = tv_sec; 00478 tcb->last_tv_usec = tv_usec; 00479 00480 *timeout = interval; 00481 } 00482 00483 #if MAINLOOP_SPEW 00484 _dbus_verbose (" timeout expires in %d milliseconds\n", *timeout); 00485 #endif 00486 00487 return *timeout == 0; 00488 } 00489 00490 dbus_bool_t 00491 _dbus_loop_dispatch (DBusLoop *loop) 00492 { 00493 00494 #if MAINLOOP_SPEW 00495 _dbus_verbose (" %d connections to dispatch\n", _dbus_list_get_length (&loop->need_dispatch)); 00496 #endif 00497 00498 if (loop->need_dispatch == NULL) 00499 return FALSE; 00500 00501 next: 00502 while (loop->need_dispatch != NULL) 00503 { 00504 DBusConnection *connection = _dbus_list_pop_first (&loop->need_dispatch); 00505 00506 while (TRUE) 00507 { 00508 DBusDispatchStatus status; 00509 00510 status = dbus_connection_dispatch (connection); 00511 00512 if (status == DBUS_DISPATCH_COMPLETE) 00513 { 00514 dbus_connection_unref (connection); 00515 goto next; 00516 } 00517 else 00518 { 00519 if (status == DBUS_DISPATCH_NEED_MEMORY) 00520 _dbus_wait_for_memory (); 00521 } 00522 } 00523 } 00524 00525 return TRUE; 00526 } 00527 00528 dbus_bool_t 00529 _dbus_loop_queue_dispatch (DBusLoop *loop, 00530 DBusConnection *connection) 00531 { 00532 if (_dbus_list_append (&loop->need_dispatch, connection)) 00533 { 00534 dbus_connection_ref (connection); 00535 return TRUE; 00536 } 00537 else 00538 return FALSE; 00539 } 00540 00541 /* Returns TRUE if we invoked any timeouts or have ready file 00542 * descriptors, which is just used in test code as a debug hack 00543 */ 00544 00545 dbus_bool_t 00546 _dbus_loop_iterate (DBusLoop *loop, 00547 dbus_bool_t block) 00548 { 00549 #define N_STACK_DESCRIPTORS 64 00550 dbus_bool_t retval; 00551 DBusPollFD *fds; 00552 DBusPollFD stack_fds[N_STACK_DESCRIPTORS]; 00553 int n_fds; 00554 int i; 00555 DBusList *link; 00556 int n_ready; 00557 int initial_serial; 00558 long timeout; 00559 dbus_bool_t oom_watch_pending; 00560 int orig_depth; 00561 DBusHashIter hash_iter; 00562 00563 retval = FALSE; 00564 00565 fds = NULL; 00566 n_fds = 0; 00567 oom_watch_pending = FALSE; 00568 orig_depth = loop->depth; 00569 00570 #if MAINLOOP_SPEW 00571 _dbus_verbose ("Iteration block=%d depth=%d timeout_count=%d watch_count=%d\n", 00572 block, loop->depth, loop->timeout_count, loop->watch_count); 00573 #endif 00574 00575 if (_dbus_hash_table_get_n_entries (loop->watches) == 0 && 00576 loop->timeouts == NULL) 00577 goto next_iteration; 00578 00579 if (loop->watch_count > N_STACK_DESCRIPTORS) 00580 { 00581 fds = dbus_new0 (DBusPollFD, loop->watch_count); 00582 00583 while (fds == NULL) 00584 { 00585 _dbus_wait_for_memory (); 00586 fds = dbus_new0 (DBusPollFD, loop->watch_count); 00587 } 00588 } 00589 else 00590 { 00591 fds = stack_fds; 00592 } 00593 00594 /* fill our array of fds and watches */ 00595 n_fds = 0; 00596 _dbus_hash_iter_init (loop->watches, &hash_iter); 00597 00598 while (_dbus_hash_iter_next (&hash_iter)) 00599 { 00600 DBusList **watches; 00601 unsigned int flags; 00602 int fd; 00603 00604 fd = _dbus_hash_iter_get_int_key (&hash_iter); 00605 watches = _dbus_hash_iter_get_value (&hash_iter); 00606 flags = 0; 00607 00608 for (link = _dbus_list_get_first_link (watches); 00609 link != NULL; 00610 link = _dbus_list_get_next_link (watches, link)) 00611 { 00612 DBusWatch *watch = link->data; 00613 00614 if (_dbus_watch_get_oom_last_time (watch)) 00615 { 00616 /* we skip this one this time, but reenable it next time, 00617 * and have a timeout on this iteration 00618 */ 00619 _dbus_watch_set_oom_last_time (watch, FALSE); 00620 oom_watch_pending = TRUE; 00621 00622 retval = TRUE; /* return TRUE here to keep the loop going, 00623 * since we don't know the watch is inactive 00624 */ 00625 00626 #if MAINLOOP_SPEW 00627 _dbus_verbose (" skipping watch on fd %d as it was out of memory last time\n", 00628 fd); 00629 #endif 00630 } 00631 else if (dbus_watch_get_enabled (watch)) 00632 { 00633 flags |= dbus_watch_get_flags (watch); 00634 } 00635 } 00636 00637 if (flags != 0) 00638 { 00639 fds[n_fds].fd = fd; 00640 fds[n_fds].revents = 0; 00641 fds[n_fds].events = watch_flags_to_poll_events (flags); 00642 00643 #if MAINLOOP_SPEW 00644 _dbus_verbose (" polling watch on fd %d %s\n", 00645 loop->fds[loop->n_fds].fd, watch_flags_to_string (flags)); 00646 #endif 00647 00648 n_fds += 1; 00649 } 00650 else 00651 { 00652 #if MAINLOOP_SPEW 00653 _dbus_verbose (" skipping disabled watch on fd %d %s\n", 00654 fd, 00655 watch_flags_to_string (dbus_watch_get_flags (watch))); 00656 #endif 00657 } 00658 } 00659 00660 timeout = -1; 00661 if (loop->timeout_count > 0) 00662 { 00663 unsigned long tv_sec; 00664 unsigned long tv_usec; 00665 00666 _dbus_get_current_time (&tv_sec, &tv_usec); 00667 00668 link = _dbus_list_get_first_link (&loop->timeouts); 00669 while (link != NULL) 00670 { 00671 DBusList *next = _dbus_list_get_next_link (&loop->timeouts, link); 00672 TimeoutCallback *tcb = link->data; 00673 00674 if (dbus_timeout_get_enabled (tcb->timeout)) 00675 { 00676 int msecs_remaining; 00677 00678 check_timeout (tv_sec, tv_usec, tcb, &msecs_remaining); 00679 00680 if (timeout < 0) 00681 timeout = msecs_remaining; 00682 else 00683 timeout = MIN (msecs_remaining, timeout); 00684 00685 #if MAINLOOP_SPEW 00686 _dbus_verbose (" timeout added, %d remaining, aggregate timeout %ld\n", 00687 msecs_remaining, timeout); 00688 #endif 00689 00690 _dbus_assert (timeout >= 0); 00691 00692 if (timeout == 0) 00693 break; /* it's not going to get shorter... */ 00694 } 00695 #if MAINLOOP_SPEW 00696 else 00697 { 00698 _dbus_verbose (" skipping disabled timeout\n"); 00699 } 00700 #endif 00701 00702 link = next; 00703 } 00704 } 00705 00706 /* Never block if we have stuff to dispatch */ 00707 if (!block || loop->need_dispatch != NULL) 00708 { 00709 timeout = 0; 00710 #if MAINLOOP_SPEW 00711 _dbus_verbose (" timeout is 0 as we aren't blocking\n"); 00712 #endif 00713 } 00714 00715 /* if a watch is OOM, don't wait longer than the OOM 00716 * wait to re-enable it 00717 */ 00718 if (oom_watch_pending) 00719 timeout = MIN (timeout, _dbus_get_oom_wait ()); 00720 00721 #if MAINLOOP_SPEW 00722 _dbus_verbose (" polling on %d descriptors timeout %ld\n", n_fds, timeout); 00723 #endif 00724 00725 n_ready = _dbus_poll (fds, n_fds, timeout); 00726 00727 initial_serial = loop->callback_list_serial; 00728 00729 if (loop->timeout_count > 0) 00730 { 00731 unsigned long tv_sec; 00732 unsigned long tv_usec; 00733 00734 _dbus_get_current_time (&tv_sec, &tv_usec); 00735 00736 /* It'd be nice to avoid this O(n) thingy here */ 00737 link = _dbus_list_get_first_link (&loop->timeouts); 00738 while (link != NULL) 00739 { 00740 DBusList *next = _dbus_list_get_next_link (&loop->timeouts, link); 00741 TimeoutCallback *tcb = link->data; 00742 00743 if (initial_serial != loop->callback_list_serial) 00744 goto next_iteration; 00745 00746 if (loop->depth != orig_depth) 00747 goto next_iteration; 00748 00749 if (dbus_timeout_get_enabled (tcb->timeout)) 00750 { 00751 int msecs_remaining; 00752 00753 if (check_timeout (tv_sec, tv_usec, 00754 tcb, &msecs_remaining)) 00755 { 00756 /* Save last callback time and fire this timeout */ 00757 tcb->last_tv_sec = tv_sec; 00758 tcb->last_tv_usec = tv_usec; 00759 00760 #if MAINLOOP_SPEW 00761 _dbus_verbose (" invoking timeout\n"); 00762 #endif 00763 00764 /* can theoretically return FALSE on OOM, but we just 00765 * let it fire again later - in practice that's what 00766 * every wrapper callback in dbus-daemon used to do */ 00767 dbus_timeout_handle (tcb->timeout); 00768 00769 retval = TRUE; 00770 } 00771 else 00772 { 00773 #if MAINLOOP_SPEW 00774 _dbus_verbose (" timeout has not expired\n"); 00775 #endif 00776 } 00777 } 00778 #if MAINLOOP_SPEW 00779 else 00780 { 00781 _dbus_verbose (" skipping invocation of disabled timeout\n"); 00782 } 00783 #endif 00784 00785 link = next; 00786 } 00787 } 00788 00789 if (n_ready > 0) 00790 { 00791 for (i = 0; i < n_fds; i++) 00792 { 00793 DBusList **watches; 00794 DBusList *next; 00795 unsigned int condition; 00796 00797 /* FIXME I think this "restart if we change the watches" 00798 * approach could result in starving watches 00799 * toward the end of the list. 00800 */ 00801 if (initial_serial != loop->callback_list_serial) 00802 goto next_iteration; 00803 00804 if (loop->depth != orig_depth) 00805 goto next_iteration; 00806 00807 if (fds[i].revents == 0) 00808 continue; 00809 00810 if (_DBUS_UNLIKELY (fds[i].revents & _DBUS_POLLNVAL)) 00811 { 00812 cull_watches_for_invalid_fd (loop, fds[i].fd); 00813 goto next_iteration; 00814 } 00815 00816 condition = watch_flags_from_poll_revents (fds[i].revents); 00817 00818 /* condition may still be 0 if we got some 00819 * weird POLLFOO thing like POLLWRBAND 00820 */ 00821 if (condition == 0) 00822 continue; 00823 00824 watches = _dbus_hash_table_lookup_int (loop->watches, fds[i].fd); 00825 00826 if (watches == NULL) 00827 continue; 00828 00829 for (link = _dbus_list_get_first_link (watches); 00830 link != NULL; 00831 link = next) 00832 { 00833 DBusWatch *watch = link->data; 00834 00835 next = _dbus_list_get_next_link (watches, link); 00836 00837 if (dbus_watch_get_enabled (watch)) 00838 { 00839 dbus_bool_t oom; 00840 00841 oom = !dbus_watch_handle (watch, condition); 00842 00843 if (oom) 00844 { 00845 _dbus_watch_set_oom_last_time (watch, TRUE); 00846 } 00847 00848 #if MAINLOOP_SPEW 00849 _dbus_verbose (" Invoked watch, oom = %d\n", oom); 00850 #endif 00851 retval = TRUE; 00852 00853 /* We re-check this every time, in case the callback 00854 * added/removed watches, which might make our position in 00855 * the linked list invalid. See the FIXME above. */ 00856 if (initial_serial != loop->callback_list_serial) 00857 goto next_iteration; 00858 00859 if (loop->depth != orig_depth) 00860 goto next_iteration; 00861 } 00862 } 00863 } 00864 } 00865 00866 next_iteration: 00867 #if MAINLOOP_SPEW 00868 _dbus_verbose (" moving to next iteration\n"); 00869 #endif 00870 00871 if (fds && fds != stack_fds) 00872 dbus_free (fds); 00873 00874 if (_dbus_loop_dispatch (loop)) 00875 retval = TRUE; 00876 00877 #if MAINLOOP_SPEW 00878 _dbus_verbose ("Returning %d\n", retval); 00879 #endif 00880 00881 return retval; 00882 } 00883 00884 void 00885 _dbus_loop_run (DBusLoop *loop) 00886 { 00887 int our_exit_depth; 00888 00889 _dbus_assert (loop->depth >= 0); 00890 00891 _dbus_loop_ref (loop); 00892 00893 our_exit_depth = loop->depth; 00894 loop->depth += 1; 00895 00896 _dbus_verbose ("Running main loop, depth %d -> %d\n", 00897 loop->depth - 1, loop->depth); 00898 00899 while (loop->depth != our_exit_depth) 00900 _dbus_loop_iterate (loop, TRUE); 00901 00902 _dbus_loop_unref (loop); 00903 } 00904 00905 void 00906 _dbus_loop_quit (DBusLoop *loop) 00907 { 00908 _dbus_assert (loop->depth > 0); 00909 00910 loop->depth -= 1; 00911 00912 _dbus_verbose ("Quit main loop, depth %d -> %d\n", 00913 loop->depth + 1, loop->depth); 00914 } 00915 00916 int 00917 _dbus_get_oom_wait (void) 00918 { 00919 #ifdef DBUS_BUILD_TESTS 00920 /* make tests go fast */ 00921 return 0; 00922 #else 00923 return 500; 00924 #endif 00925 } 00926 00927 void 00928 _dbus_wait_for_memory (void) 00929 { 00930 _dbus_verbose ("Waiting for more memory\n"); 00931 _dbus_sleep_milliseconds (_dbus_get_oom_wait ()); 00932 } 00933 00934 #endif /* !DOXYGEN_SHOULD_SKIP_THIS */
1.7.5.1