diff options
Diffstat (limited to 'dbus/dbus-transport-unix.c')
| -rw-r--r-- | dbus/dbus-transport-unix.c | 167 | 
1 files changed, 122 insertions, 45 deletions
diff --git a/dbus/dbus-transport-unix.c b/dbus/dbus-transport-unix.c index f7a49af2..a33b8f78 100644 --- a/dbus/dbus-transport-unix.c +++ b/dbus/dbus-transport-unix.c @@ -1,7 +1,7 @@  /* -*- mode: C; c-file-style: "gnu" -*- */  /* dbus-transport-unix.c UNIX socket subclasses of DBusTransport   * - * Copyright (C) 2002, 2003  Red Hat Inc. + * Copyright (C) 2002, 2003, 2004  Red Hat Inc.   *   * Licensed under the Academic Free License version 2.1   *  @@ -114,7 +114,7 @@ static void  check_write_watch (DBusTransport *transport)  {    DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport; -  dbus_bool_t need_write_watch; +  dbus_bool_t needed;    if (transport->connection == NULL)      return; @@ -128,14 +128,37 @@ check_write_watch (DBusTransport *transport)    _dbus_transport_ref (transport);    if (_dbus_transport_get_is_authenticated (transport)) -    need_write_watch = transport->messages_need_sending; +    needed = _dbus_connection_has_messages_to_send_unlocked (transport->connection);    else -    need_write_watch = transport->send_credentials_pending || -      _dbus_auth_do_work (transport->auth) == DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND; +    { +      if (transport->send_credentials_pending) +        needed = TRUE; +      else +        { +          DBusAuthState auth_state; +           +          auth_state = _dbus_auth_do_work (transport->auth); +           +          /* If we need memory we install the write watch just in case, +           * if there's no need for it, it will get de-installed +           * next time we try reading. +           */ +          if (auth_state == DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND || +              auth_state == DBUS_AUTH_STATE_WAITING_FOR_MEMORY) +            needed = TRUE; +          else +            needed = FALSE; +        } +    } + +  _dbus_verbose ("check_write_watch(): needed = %d on connection %p watch %p fd = %d outgoing messages exist %d\n", +                 needed, transport->connection, unix_transport->write_watch, +                 unix_transport->fd, +                 _dbus_connection_has_messages_to_send_unlocked (transport->connection));    _dbus_connection_toggle_watch (transport->connection,                                   unix_transport->write_watch, -                                 need_write_watch); +                                 needed);    _dbus_transport_unref (transport);  } @@ -146,6 +169,9 @@ check_read_watch (DBusTransport *transport)    DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;    dbus_bool_t need_read_watch; +  _dbus_verbose ("%s: fd = %d\n", +                 _DBUS_FUNCTION_NAME, unix_transport->fd); +      if (transport->connection == NULL)      return; @@ -161,9 +187,35 @@ check_read_watch (DBusTransport *transport)      need_read_watch =        _dbus_counter_get_value (transport->live_messages_size) < transport->max_live_messages_size;    else -    need_read_watch = transport->receive_credentials_pending || -      _dbus_auth_do_work (transport->auth) == DBUS_AUTH_STATE_WAITING_FOR_INPUT; +    { +      if (transport->receive_credentials_pending) +        need_read_watch = TRUE; +      else +        { +          /* The reason to disable need_read_watch when not WAITING_FOR_INPUT +           * is to avoid spinning on the file descriptor when we're waiting +           * to write or for some other part of the auth process +           */ +          DBusAuthState auth_state; +           +          auth_state = _dbus_auth_do_work (transport->auth); + +          /* If we need memory we install the read watch just in case, +           * if there's no need for it, it will get de-installed +           * next time we try reading. If we're authenticated we +           * install it since we normally have it installed while +           * authenticated. +           */ +          if (auth_state == DBUS_AUTH_STATE_WAITING_FOR_INPUT || +              auth_state == DBUS_AUTH_STATE_WAITING_FOR_MEMORY || +              auth_state == DBUS_AUTH_STATE_AUTHENTICATED) +            need_read_watch = TRUE; +          else +            need_read_watch = FALSE; +        } +    } +  _dbus_verbose ("  setting read watch enabled = %d\n", need_read_watch);    _dbus_connection_toggle_watch (transport->connection,                                   unix_transport->read_watch,                                   need_read_watch); @@ -326,12 +378,24 @@ do_authentication (DBusTransport *transport,  {    dbus_bool_t oom;    dbus_bool_t orig_auth_state; -   -  _dbus_transport_ref (transport);    oom = FALSE;    orig_auth_state = _dbus_transport_get_is_authenticated (transport); + +  /* This is essential to avoid the check_write_watch() at the end, +   * we don't want to add a write watch in do_iteration before +   * we try writing and get EAGAIN +   */ +  if (orig_auth_state) +    { +      if (auth_completed) +        *auth_completed = FALSE; +      return TRUE; +    } +   +  _dbus_transport_ref (transport); +      while (!_dbus_transport_get_is_authenticated (transport) &&           _dbus_transport_get_is_connected (transport))      {       @@ -418,16 +482,17 @@ do_writing (DBusTransport *transport)        return TRUE;      } -#if 0 -  _dbus_verbose ("do_writing(), have_messages = %d\n", -                 _dbus_connection_have_messages_to_send (transport->connection)); +#if 1 +  _dbus_verbose ("do_writing(), have_messages = %d, fd = %d\n", +                 _dbus_connection_has_messages_to_send_unlocked (transport->connection), +                 unix_transport->fd);  #endif    oom = FALSE;    total = 0;    while (!transport->disconnected && -         _dbus_connection_have_messages_to_send (transport->connection)) +         _dbus_connection_has_messages_to_send_unlocked (transport->connection))      {        int bytes_written;        DBusMessage *message; @@ -442,12 +507,6 @@ do_writing (DBusTransport *transport)                           total, unix_transport->max_bytes_written_per_iteration);            goto out;          } - -      if (!dbus_watch_get_enabled (unix_transport->write_watch)) -        { -          _dbus_verbose ("write watch disabled, not writing more stuff\n"); -          goto out; -        }        message = _dbus_connection_get_message_to_send (transport->connection);        _dbus_assert (message != NULL); @@ -580,6 +639,9 @@ do_reading (DBusTransport *transport)    int total;    dbus_bool_t oom; +  _dbus_verbose ("%s: fd = %d\n", _DBUS_FUNCTION_NAME, +                 unix_transport->fd); +      /* No messages without authentication! */    if (!_dbus_transport_get_is_authenticated (transport))      return TRUE; @@ -722,6 +784,7 @@ unix_handle_watch (DBusTransport *transport,    _dbus_assert (watch == unix_transport->read_watch ||                  watch == unix_transport->write_watch); +  _dbus_assert (watch != NULL);    /* Disconnect in case of an error.  In case of hangup do not     * disconnect the transport because data can still be in the buffer @@ -741,8 +804,9 @@ unix_handle_watch (DBusTransport *transport,        (flags & DBUS_WATCH_READABLE))      {        dbus_bool_t auth_finished; -#if 0 -      _dbus_verbose ("handling read watch (%x)\n", flags); +#if 1 +      _dbus_verbose ("handling read watch %p flags = %x\n", +                     watch, flags);  #endif        if (!do_authentication (transport, TRUE, FALSE, &auth_finished))          return FALSE; @@ -761,13 +825,17 @@ unix_handle_watch (DBusTransport *transport,  	      return FALSE;  	    }  	} +      else +        { +          _dbus_verbose ("Not reading anything since we just completed the authentication\n"); +        }      }    else if (watch == unix_transport->write_watch &&             (flags & DBUS_WATCH_WRITABLE))      { -#if 0 -      _dbus_verbose ("handling write watch, messages_need_sending = %d\n", -                     transport->messages_need_sending); +#if 1 +      _dbus_verbose ("handling write watch, have_outgoing_messages = %d\n", +                     _dbus_connection_has_messages_to_send_unlocked (transport->connection));  #endif        if (!do_authentication (transport, FALSE, TRUE, NULL))          return FALSE; @@ -777,6 +845,9 @@ unix_handle_watch (DBusTransport *transport,            _dbus_verbose ("no memory to write\n");            return FALSE;          } + +      /* See if we still need the write watch */ +      check_write_watch (transport);      }  #ifdef DBUS_ENABLE_VERBOSE_MODE    else @@ -838,13 +909,6 @@ unix_connection_set (DBusTransport *transport)    return TRUE;  } -static void -unix_messages_pending (DBusTransport *transport, -                       int            messages_pending) -{ -  check_write_watch (transport); -} -  /**   * @todo We need to have a way to wake up the select sleep if   * a new iteration request comes in with a flag (read/write) that @@ -862,20 +926,18 @@ unix_do_iteration (DBusTransport *transport,    int poll_res;    int poll_timeout; -  _dbus_verbose (" iteration flags = %s%s timeout = %d read_watch = %p write_watch = %p\n", +  _dbus_verbose (" iteration flags = %s%s timeout = %d read_watch = %p write_watch = %p fd = %d\n",                   flags & DBUS_ITERATION_DO_READING ? "read" : "",                   flags & DBUS_ITERATION_DO_WRITING ? "write" : "",                   timeout_milliseconds,                   unix_transport->read_watch, -                 unix_transport->write_watch); +                 unix_transport->write_watch, +                 unix_transport->fd);    /* the passed in DO_READING/DO_WRITING flags indicate whether to     * read/write messages, but regardless of those we may need to block     * for reading/writing to do auth.  But if we do reading for auth,     * we don't want to read any messages yet if not given DO_READING. -   * -   * Also, if read_watch == NULL or write_watch == NULL, we don't -   * want to read/write so don't.     */    poll_fd.fd = unix_transport->fd; @@ -883,12 +945,12 @@ unix_do_iteration (DBusTransport *transport,    if (_dbus_transport_get_is_authenticated (transport))      { -      if (unix_transport->read_watch && -          (flags & DBUS_ITERATION_DO_READING)) +      _dbus_assert (unix_transport->read_watch); +      if (flags & DBUS_ITERATION_DO_READING)  	poll_fd.events |= _DBUS_POLLIN; -       -      if (unix_transport->write_watch && -          (flags & DBUS_ITERATION_DO_WRITING)) + +      _dbus_assert (unix_transport->write_watch); +      if (flags & DBUS_ITERATION_DO_WRITING)  	poll_fd.events |= _DBUS_POLLOUT;      }    else @@ -904,7 +966,7 @@ unix_do_iteration (DBusTransport *transport,        if (transport->send_credentials_pending ||            auth_state == DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND)  	poll_fd.events |= _DBUS_POLLOUT; -    }  +    }    if (poll_fd.events)      { @@ -947,7 +1009,7 @@ unix_do_iteration (DBusTransport *transport,  	      /* See comment in unix_handle_watch. */  	      if (authentication_completed) -		return; +                goto out;                if (need_read && (flags & DBUS_ITERATION_DO_READING))                  do_reading (transport); @@ -961,6 +1023,22 @@ unix_do_iteration (DBusTransport *transport,                           _dbus_strerror (errno));          }      } + + + out: +  /* We need to install the write watch only if we did not +   * successfully write everything. Note we need to be careful that we +   * don't call check_write_watch *before* do_writing, since it's +   * inefficient to add the write watch, and we can avoid it most of +   * the time since we can write immediately. +   *  +   * However, we MUST always call check_write_watch(); DBusConnection code +   * relies on the fact that running an iteration will notice that +   * messages are pending. +   */ +  check_write_watch (transport); + +  _dbus_verbose (" ... leaving do_iteration()\n");  }  static void @@ -987,7 +1065,6 @@ static DBusTransportVTable unix_vtable = {    unix_handle_watch,    unix_disconnect,    unix_connection_set, -  unix_messages_pending,    unix_do_iteration,    unix_live_messages_changed,    unix_get_unix_fd  | 
