[PATCH] Have pending call keep a ref to its connection (fixes the NetworkManager crash)

Havoc Pennington hp at redhat.com
Thu Jul 13 14:50:43 PDT 2006


John (J5) Palmieri wrote:
> I opted to send TRUE and set the pending_reply = NULL.  If this breaks
> apps they should have been checking for it in the first place (and now
> is the time to break apps).  It is the simplest code path and easy to
> fix in apps that are broken.

Sounds fine, no better ideas from me. I'd be sure it's in the docs though.

>> +
>> +  CONNECTION_LOCK (connection);
>> +
>> +   if (!_dbus_connection_get_is_connected_unlocked (connection))
>> +    {
>> +      /* throw a warning here so we can see if this happens often 
>> +         and perhaps handle it in a better way (e.g. throw an error in
>> +         the pending call) */
>> +      _dbus_warn ("dbus_connection_send_with_reply called on a disconnected connection");
>> +      CONNECTION_UNLOCK (connection);
>> +
>> +      *pending_return = NULL;
>> +
>> +      return TRUE;
>> +    }

I don't think we should warn *and* document that it sets the pending 
call to null; otherwise people can do something legitimate that has a 
warning they can't get rid of. If it warns it should be due to someone 
making a programming error. There is no thread-safe way right now 
someone could avoid sending messages on a disconnected connection.

>>  static void
>> +connection_timeout_and_complete_all_pending_calls (DBusConnection *connection)
>> +{
>> +  DBusHashIter iter;
>> +
>> +  _dbus_hash_iter_init (connection->pending_replies, &iter);
>> +
>> +  /* create list while we remove the iters from the hash
>> +     because we need to go over it a couple of times */
>> +  while (_dbus_hash_iter_next (&iter))
>> +    {
>> +      DBusPendingCall *pending;
>> +      DBusDispatchStatus status;  
>> + 
>> +      pending = (DBusPendingCall *) _dbus_hash_iter_get_value (&iter);
>> +      dbus_pending_call_ref (pending);
>> +     
>> +      _dbus_pending_call_queue_timeout_error (pending, 
>> +                                              connection);
>> +      _dbus_connection_remove_timeout_unlocked (connection,
>> +                                                _dbus_pending_call_get_timeout (pending));
>> +
>> +      status = _dbus_connection_get_dispatch_status_unlocked (connection);
>> +
>> +      /* Unlocks, and calls out to user code */
>> +      _dbus_connection_update_dispatch_status_and_unlock (connection, status);
>> +
>> +      /* lock it again */
>> +      CONNECTION_LOCK (connection);
>> +   
>> +      _dbus_hash_iter_remove_entry (&iter);
>> +
>> +      dbus_pending_call_unref (pending);
>> +      
>> +    }

The unlocking and updating dispatch status can be outside the loop I 
think, in fact it should be a lot safer and more efficient that way.

>>                                    DBUS_INTERFACE_LOCAL,
>>                                    "Disconnected"))
>>          {
>> +          /* timeout all active pending calls */
>> +          connection_timeout_and_complete_all_pending_calls (connection);
>> +

This will put the timeouts *after* the disconnect message; instead, 
should time them all out just before where we currently *queue* the 
disconnect message.

>> +  if (pending->connection != NULL)
>> +    dbus_connection_ref (pending->connection);
>> +

This != null check should be obsolete right?

Havoc



More information about the dbus mailing list