<span class="gmail_quote"><br></span><span class="q">On 7/18/07, <b class="gmail_sendername">Havoc Pennington</b> &lt;<a href="mailto:hp@redhat.com" target="_blank" onclick="return top.js.OpenExtLink(window,event,this)">hp@redhat.com
</a>&gt; wrote:</span><div><span class="q"><span class="gmail_quote"></span><br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
The hard thing is that the patch to call the callback at the end has to<br>change every function in the call stack, more or less. Another headache<br>here is that the connection lock has to be held until we stop using the
<br>connection-&gt;timeouts object, so maybe dbus_timeout_list_add_timeout is<br>changed to return the app callback as an invokable closure or something<br>of that nature, and then the closure is passed up the call stack until
<br>we can unlock and invoke it. The closure would store<br>timeout_list-&gt;add_timeout_function and timeout_list-&gt;timeout_data, but<br>could not have a pointer to the timeout_list itself since that is<br>protected by the connection lock.
</blockquote></span><div><br>Would this actually work?&nbsp;&nbsp; I think this
has other issues.&nbsp;&nbsp; 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.
<br><br>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.<br><br><pre>typedef struct DBusTimeoutClosure<br><br>{<br><br>DBusTimeoutAppCallback&nbsp; app_callback;
<br><br><br>DBusTimeout* timeout;<br><br>void* app_callback_data;<br><br>DBusTimeoutFailureCallback failure_callback<br><br>void* failure_callback_data<span class="q"><br><br>};<br>static dbus_bool_t<br><br>protected_change_timeout (DBusConnection           *connection,
<br><br>                          DBusTimeout              *timeout,<br>                          DBusTimeoutAddFunction    add_function,<br>                          DBusTimeoutRemoveFunction remove_function,<br><br>                          DBusTimeoutToggleFunction toggle_function,
<br><br>                          dbus_bool_t               enabled)<br>{<br>  DBusTimeoutList *timeouts;<br>  dbus_bool_t retval;<br></span>  DBusTimeoutClosure * closure;<br>  dbus_bool_t app_retval;<br><br>  HAVE_LOCK_CHECK (connection);
<br><br>      if (add_function)<br>        retval = (* add_function) (connection-&gt;timeouts, timeout, &amp;closure);<span class="q"><br><br>      else if (remove_function)<br>        {<br>          retval = TRUE;<br><br>
</span>          (* remove_function) (connection-&gt;timeouts, timeout, &amp;closure);<br>        }<br>      else<br>        {<br>          retval = TRUE;<br>          (* toggle_function) (connection-&gt;timeouts, timeout, enabled, &amp;closure);
<br><span class="q"><br><br>        }<br>      _dbus_connection_ref_unlocked (connection);<br>      CONNECTION_UNLOCK (connection);<br></span>      if(closure)<br>          app_retval = closure-&gt;app_callback(timeout, app_callback_data);
<br>      CONNECTION_LOCK (connection);<br><span class="q"><br>      _dbus_connection_unref_unlocked (connection);<br></span>      if(closure)<br>          if(!app_retval)<br>          {<br>               retval = closure-&gt;failure_callback(connection-&gt;timeouts, timeout, failure_callback_data);
<br><br>          }<br><br><br>      return retval;<br><br><br>}</pre></div><span class="q"><br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
A full fix for the reentrancy would probably involve adding a separate
<br>lock on the TimeoutsList or some nightmare like that. <br></blockquote><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">The simplest quick fix I can think of is to make
<br>timeout_list_add_timeout and friends return the closure thingy, then<br>where the current code does timeouts=NULL and drops the lock, don&#39;t do<br>the timeouts=NULL part since we won&#39;t need the timeout list, just the
<br>closure.</blockquote></span><div><br>I think what I describe above is close to this, but I&#39;m not completely sure.<br>&nbsp;</div></div>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.&nbsp; This would make them
responsible for calling this unlock function before it call out to an
application callback and to lock it right after.
<br><span class="sg"><br>Keith Preston<br></span><br>