Phantom "Out of Memory" error

keith preston keithpre at gmail.com
Wed Jul 18 09:35:13 PDT 2007


On 7/18/07, Havoc Pennington <hp at redhat.com> wrote:

> The hard thing is that the patch to call the callback at the end has to
> change every function in the call stack, more or less. Another headache
> here is that the connection lock has to be held until we stop using the
> connection->timeouts object, so maybe dbus_timeout_list_add_timeout is
> changed to return the app callback as an invokable closure or something
> of that nature, and then the closure is passed up the call stack until
> we can unlock and invoke it. The closure would store
> timeout_list->add_timeout_function and timeout_list->timeout_data, but
> could not have a pointer to the timeout_list itself since that is
> protected by the connection lock.


Would this actually work?   I think this has other issues.   Such as in the
Add_timeout case the user add_timeout function can fail and then we would
need to regain the lock and remove the timeout from the list.

If this was really how we wanted to do it I would see this as the closure
and protected_protected_change_timeout would look like this.

typedef struct DBusTimeoutClosure

{

DBusTimeoutAppCallback  app_callback;


DBusTimeout* timeout;

void* app_callback_data;

DBusTimeoutFailureCallback failure_callback

void* failure_callback_data

};
static dbus_bool_t

protected_change_timeout (DBusConnection           *connection,

                          DBusTimeout              *timeout,
                          DBusTimeoutAddFunction    add_function,
                          DBusTimeoutRemoveFunction remove_function,

                          DBusTimeoutToggleFunction toggle_function,

                          dbus_bool_t               enabled)
{
  DBusTimeoutList *timeouts;
  dbus_bool_t retval;
  DBusTimeoutClosure * closure;
  dbus_bool_t app_retval;

  HAVE_LOCK_CHECK (connection);

      if (add_function)
        retval = (* add_function) (connection->timeouts, timeout, &closure);

      else if (remove_function)
        {
          retval = TRUE;

          (* remove_function) (connection->timeouts, timeout, &closure);
        }
      else
        {
          retval = TRUE;
          (* toggle_function) (connection->timeouts, timeout, enabled,
&closure);


        }
      _dbus_connection_ref_unlocked (connection);
      CONNECTION_UNLOCK (connection);
      if(closure)
          app_retval = closure->app_callback(timeout, app_callback_data);
      CONNECTION_LOCK (connection);

      _dbus_connection_unref_unlocked (connection);
      if(closure)
          if(!app_retval)
          {
               retval =
closure->failure_callback(connection->timeouts, timeout,
failure_callback_data);

          }


      return retval;


}


A full fix for the reentrancy would probably involve adding a separate
> lock on the TimeoutsList or some nightmare like that.
>
The simplest quick fix I can think of is to make
> timeout_list_add_timeout and friends return the closure thingy, then
> where the current code does timeouts=NULL and drops the lock, don't do
> the timeouts=NULL part since we won't need the timeout list, just the
> closure.


I think what I describe above is close to this, but I'm not completely sure.

The only other way I see (which might be cleaner) is to pass a function to
lock and unlock the connection from protected_change_timeout to the
DBusTimeout{Add,Remove,Toggle}Functions.  This would make them responsible
for calling this unlock function before it call out to an application
callback and to lock it right after.

Keith Preston
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.freedesktop.org/archives/dbus/attachments/20070718/f11c3841/attachment.htm 


More information about the dbus mailing list