X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dbus%2Fdbus-mainloop.c;h=cef676a3a9723710a8921eac30fe382485630ae9;hb=757b80b9711d9733798c927495d74c7323e95400;hp=1a046a1f58deb99629c0331be97cad0d00247027;hpb=ef8d0d75d538db543ab0ff68809656f3972e3848;p=platform%2Fupstream%2Fdbus.git diff --git a/dbus/dbus-mainloop.c b/dbus/dbus-mainloop.c index 1a046a1..cef676a 100644 --- a/dbus/dbus-mainloop.c +++ b/dbus/dbus-mainloop.c @@ -1,7 +1,8 @@ /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-mainloop.c Main loop utility * - * Copyright (C) 2003, 2004 Red Hat, Inc. + * Copyright © 2003, 2004 Red Hat, Inc. + * Copyright © 2011 Nokia Corporation * * Licensed under the Academic Free License version 2.1 * @@ -28,7 +29,7 @@ #include #include -#include +#include #include #define MAINLOOP_SPEW 0 @@ -59,44 +60,18 @@ struct DBusLoop int refcount; /** fd => dbus_malloc'd DBusList ** of references to DBusWatch */ DBusHashTable *watches; + DBusSocketSet *socket_set; DBusList *timeouts; int callback_list_serial; int watch_count; int timeout_count; int depth; /**< number of recursive runs */ DBusList *need_dispatch; + /** TRUE if we will skip a watch next time because it was OOM; becomes + * FALSE between polling, and dealing with the results of the poll */ + unsigned oom_watch_pending : 1; }; -static short -watch_flags_to_poll_events (unsigned int flags) -{ - short events = 0; - - if (flags & DBUS_WATCH_READABLE) - events |= _DBUS_POLLIN; - if (flags & DBUS_WATCH_WRITABLE) - events |= _DBUS_POLLOUT; - - return events; -} - -static unsigned int -watch_flags_from_poll_revents (short revents) -{ - unsigned int condition = 0; - - if (revents & _DBUS_POLLIN) - condition |= DBUS_WATCH_READABLE; - if (revents & _DBUS_POLLOUT) - condition |= DBUS_WATCH_WRITABLE; - if (revents & _DBUS_POLLHUP) - condition |= DBUS_WATCH_HANGUP; - if (revents & _DBUS_POLLERR) - condition |= DBUS_WATCH_ERROR; - - return condition; -} - typedef struct { DBusTimeout *timeout; @@ -116,8 +91,8 @@ timeout_callback_new (DBusTimeout *timeout) return NULL; cb->timeout = timeout; - _dbus_get_current_time (&cb->last_tv_sec, - &cb->last_tv_usec); + _dbus_get_monotonic_time (&cb->last_tv_sec, + &cb->last_tv_usec); return cb; } @@ -161,8 +136,16 @@ _dbus_loop_new (void) loop->watches = _dbus_hash_table_new (DBUS_HASH_INT, NULL, free_watch_table_entry); - if (loop->watches == NULL) + loop->socket_set = _dbus_socket_set_new (0); + + if (loop->watches == NULL || loop->socket_set == NULL) { + if (loop->watches != NULL) + _dbus_hash_table_unref (loop->watches); + + if (loop->socket_set != NULL) + _dbus_socket_set_free (loop->socket_set); + dbus_free (loop); return NULL; } @@ -200,6 +183,7 @@ _dbus_loop_unref (DBusLoop *loop) } _dbus_hash_table_unref (loop->watches); + _dbus_socket_set_free (loop->socket_set); dbus_free (loop); } } @@ -250,20 +234,57 @@ cull_watches_for_invalid_fd (DBusLoop *loop, _dbus_hash_table_remove_int (loop->watches, fd); } -static void +static dbus_bool_t gc_watch_table_entry (DBusLoop *loop, DBusList **watches, int fd) { /* If watches is already NULL we have nothing to do */ if (watches == NULL) - return; + return FALSE; /* We can't GC hash table entries if they're non-empty lists */ if (*watches != NULL) - return; + return FALSE; _dbus_hash_table_remove_int (loop->watches, fd); + return TRUE; +} + +static void +refresh_watches_for_fd (DBusLoop *loop, + DBusList **watches, + int fd) +{ + DBusList *link; + unsigned int flags = 0; + dbus_bool_t interested = FALSE; + + _dbus_assert (fd != -1); + + if (watches == NULL) + watches = _dbus_hash_table_lookup_int (loop->watches, fd); + + /* we allocated this in the first _dbus_loop_add_watch for the fd, and keep + * it until there are none left */ + _dbus_assert (watches != NULL); + + for (link = _dbus_list_get_first_link (watches); + link != NULL; + link = _dbus_list_get_next_link (watches, link)) + { + if (dbus_watch_get_enabled (link->data) && + !_dbus_watch_get_oom_last_time (link->data)) + { + flags |= dbus_watch_get_flags (link->data); + interested = TRUE; + } + } + + if (interested) + _dbus_socket_set_enable (loop->socket_set, fd, flags); + else + _dbus_socket_set_disable (loop->socket_set, fd); } dbus_bool_t @@ -281,23 +302,43 @@ _dbus_loop_add_watch (DBusLoop *loop, if (watches == NULL) return FALSE; - if (_dbus_list_append (watches, _dbus_watch_ref (watch))) - { - loop->callback_list_serial += 1; - loop->watch_count += 1; - } - else + if (!_dbus_list_append (watches, _dbus_watch_ref (watch))) { _dbus_watch_unref (watch); gc_watch_table_entry (loop, watches, fd); - return FALSE; - } + return FALSE; + } + + if (_dbus_list_length_is_one (watches)) + { + if (!_dbus_socket_set_add (loop->socket_set, fd, + dbus_watch_get_flags (watch), + dbus_watch_get_enabled (watch))) + { + _dbus_hash_table_remove_int (loop->watches, fd); + return FALSE; + } + } + else + { + /* we're modifying, not adding, which can't fail with OOM */ + refresh_watches_for_fd (loop, watches, fd); + } + loop->callback_list_serial += 1; + loop->watch_count += 1; return TRUE; } void +_dbus_loop_toggle_watch (DBusLoop *loop, + DBusWatch *watch) +{ + refresh_watches_for_fd (loop, NULL, dbus_watch_get_socket (watch)); +} + +void _dbus_loop_remove_watch (DBusLoop *loop, DBusWatch *watch) { @@ -329,8 +370,11 @@ _dbus_loop_remove_watch (DBusLoop *loop, _dbus_watch_unref (this); /* if that was the last watch for that fd, drop the hash table - * entry too */ - gc_watch_table_entry (loop, watches, fd); + * entry, and stop reserving space for it in the socket set */ + if (gc_watch_table_entry (loop, watches, fd)) + { + _dbus_socket_set_remove (loop->socket_set, fd); + } return; } @@ -548,23 +592,16 @@ _dbus_loop_iterate (DBusLoop *loop, { #define N_STACK_DESCRIPTORS 64 dbus_bool_t retval; - DBusPollFD *fds; - DBusPollFD stack_fds[N_STACK_DESCRIPTORS]; - int n_fds; + DBusSocketEvent ready_fds[N_STACK_DESCRIPTORS]; int i; DBusList *link; int n_ready; int initial_serial; long timeout; - dbus_bool_t oom_watch_pending; int orig_depth; - DBusHashIter hash_iter; retval = FALSE; - fds = NULL; - n_fds = 0; - oom_watch_pending = FALSE; orig_depth = loop->depth; #if MAINLOOP_SPEW @@ -576,94 +613,13 @@ _dbus_loop_iterate (DBusLoop *loop, loop->timeouts == NULL) goto next_iteration; - if (loop->watch_count > N_STACK_DESCRIPTORS) - { - fds = dbus_new0 (DBusPollFD, loop->watch_count); - - while (fds == NULL) - { - _dbus_wait_for_memory (); - fds = dbus_new0 (DBusPollFD, loop->watch_count); - } - } - else - { - fds = stack_fds; - } - - /* fill our array of fds and watches */ - n_fds = 0; - _dbus_hash_iter_init (loop->watches, &hash_iter); - - while (_dbus_hash_iter_next (&hash_iter)) - { - DBusList **watches; - unsigned int flags; - int fd; - - fd = _dbus_hash_iter_get_int_key (&hash_iter); - watches = _dbus_hash_iter_get_value (&hash_iter); - flags = 0; - - for (link = _dbus_list_get_first_link (watches); - link != NULL; - link = _dbus_list_get_next_link (watches, link)) - { - DBusWatch *watch = link->data; - - if (_dbus_watch_get_oom_last_time (watch)) - { - /* we skip this one this time, but reenable it next time, - * and have a timeout on this iteration - */ - _dbus_watch_set_oom_last_time (watch, FALSE); - oom_watch_pending = TRUE; - - retval = TRUE; /* return TRUE here to keep the loop going, - * since we don't know the watch is inactive - */ - -#if MAINLOOP_SPEW - _dbus_verbose (" skipping watch on fd %d as it was out of memory last time\n", - fd); -#endif - } - else if (dbus_watch_get_enabled (watch)) - { - flags |= dbus_watch_get_flags (watch); - } - } - - if (flags != 0) - { - fds[n_fds].fd = fd; - fds[n_fds].revents = 0; - fds[n_fds].events = watch_flags_to_poll_events (flags); - -#if MAINLOOP_SPEW - _dbus_verbose (" polling watch on fd %d %s\n", - loop->fds[loop->n_fds].fd, watch_flags_to_string (flags)); -#endif - - n_fds += 1; - } - else - { -#if MAINLOOP_SPEW - _dbus_verbose (" skipping disabled watch on fd %d %s\n", - fd, - watch_flags_to_string (dbus_watch_get_flags (watch))); -#endif - } - } - timeout = -1; if (loop->timeout_count > 0) { unsigned long tv_sec; unsigned long tv_usec; - _dbus_get_current_time (&tv_sec, &tv_usec); + _dbus_get_monotonic_time (&tv_sec, &tv_usec); link = _dbus_list_get_first_link (&loop->timeouts); while (link != NULL) @@ -712,17 +668,58 @@ _dbus_loop_iterate (DBusLoop *loop, #endif } - /* if a watch is OOM, don't wait longer than the OOM + /* if a watch was OOM last time, don't wait longer than the OOM * wait to re-enable it */ - if (oom_watch_pending) + if (loop->oom_watch_pending) timeout = MIN (timeout, _dbus_get_oom_wait ()); #if MAINLOOP_SPEW _dbus_verbose (" polling on %d descriptors timeout %ld\n", n_fds, timeout); #endif - - n_ready = _dbus_poll (fds, n_fds, timeout); + + n_ready = _dbus_socket_set_poll (loop->socket_set, ready_fds, + _DBUS_N_ELEMENTS (ready_fds), timeout); + + /* re-enable any watches we skipped this time */ + if (loop->oom_watch_pending) + { + DBusHashIter hash_iter; + + loop->oom_watch_pending = FALSE; + + _dbus_hash_iter_init (loop->watches, &hash_iter); + + while (_dbus_hash_iter_next (&hash_iter)) + { + DBusList **watches; + int fd; + dbus_bool_t changed; + + changed = FALSE; + fd = _dbus_hash_iter_get_int_key (&hash_iter); + watches = _dbus_hash_iter_get_value (&hash_iter); + + for (link = _dbus_list_get_first_link (watches); + link != NULL; + link = _dbus_list_get_next_link (watches, link)) + { + DBusWatch *watch = link->data; + + if (_dbus_watch_get_oom_last_time (watch)) + { + _dbus_watch_set_oom_last_time (watch, FALSE); + changed = TRUE; + } + } + + if (changed) + refresh_watches_for_fd (loop, watches, fd); + } + + retval = TRUE; /* return TRUE here to keep the loop going, + * since we don't know the watch was inactive */ + } initial_serial = loop->callback_list_serial; @@ -731,7 +728,7 @@ _dbus_loop_iterate (DBusLoop *loop, unsigned long tv_sec; unsigned long tv_usec; - _dbus_get_current_time (&tv_sec, &tv_usec); + _dbus_get_monotonic_time (&tv_sec, &tv_usec); /* It'd be nice to avoid this O(n) thingy here */ link = _dbus_list_get_first_link (&loop->timeouts); @@ -785,14 +782,15 @@ _dbus_loop_iterate (DBusLoop *loop, link = next; } } - + if (n_ready > 0) { - for (i = 0; i < n_fds; i++) + for (i = 0; i < n_ready; i++) { DBusList **watches; DBusList *next; unsigned int condition; + dbus_bool_t any_oom; /* FIXME I think this "restart if we change the watches" * approach could result in starving watches @@ -804,16 +802,16 @@ _dbus_loop_iterate (DBusLoop *loop, if (loop->depth != orig_depth) goto next_iteration; - if (fds[i].revents == 0) - continue; + _dbus_assert (ready_fds[i].flags != 0); - if (_DBUS_UNLIKELY (fds[i].revents & _DBUS_POLLNVAL)) + if (_DBUS_UNLIKELY (ready_fds[i].flags & _DBUS_WATCH_NVAL)) { - cull_watches_for_invalid_fd (loop, fds[i].fd); + cull_watches_for_invalid_fd (loop, ready_fds[i].fd); goto next_iteration; } - condition = watch_flags_from_poll_revents (fds[i].revents); + condition = ready_fds[i].flags; + _dbus_assert ((condition & _DBUS_WATCH_NVAL) == 0); /* condition may still be 0 if we got some * weird POLLFOO thing like POLLWRBAND @@ -821,11 +819,14 @@ _dbus_loop_iterate (DBusLoop *loop, if (condition == 0) continue; - watches = _dbus_hash_table_lookup_int (loop->watches, fds[i].fd); + watches = _dbus_hash_table_lookup_int (loop->watches, + ready_fds[i].fd); if (watches == NULL) continue; + any_oom = FALSE; + for (link = _dbus_list_get_first_link (watches); link != NULL; link = next) @@ -843,6 +844,8 @@ _dbus_loop_iterate (DBusLoop *loop, if (oom) { _dbus_watch_set_oom_last_time (watch, TRUE); + loop->oom_watch_pending = TRUE; + any_oom = TRUE; } #if MAINLOOP_SPEW @@ -853,13 +856,19 @@ _dbus_loop_iterate (DBusLoop *loop, /* We re-check this every time, in case the callback * added/removed watches, which might make our position in * the linked list invalid. See the FIXME above. */ - if (initial_serial != loop->callback_list_serial) - goto next_iteration; + if (initial_serial != loop->callback_list_serial || + loop->depth != orig_depth) + { + if (any_oom) + refresh_watches_for_fd (loop, NULL, ready_fds[i].fd); - if (loop->depth != orig_depth) - goto next_iteration; + goto next_iteration; + } } } + + if (any_oom) + refresh_watches_for_fd (loop, watches, ready_fds[i].fd); } } @@ -867,9 +876,6 @@ _dbus_loop_iterate (DBusLoop *loop, #if MAINLOOP_SPEW _dbus_verbose (" moving to next iteration\n"); #endif - - if (fds && fds != stack_fds) - dbus_free (fds); if (_dbus_loop_dispatch (loop)) retval = TRUE;