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