<span class="gmail_quote"><br></span><span class="q">On 7/18/07, <b class="gmail_sendername">Havoc Pennington</b> <<a href="mailto:hp@redhat.com" target="_blank" onclick="return top.js.OpenExtLink(window,event,this)">hp@redhat.com
</a>> 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->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->add_timeout_function and timeout_list->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? 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.
<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 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->timeouts, timeout, &closure);<span class="q"><br><br> else if (remove_function)<br> {<br> retval = TRUE;<br><br>
</span> (* remove_function) (connection->timeouts, timeout, &closure);<br> }<br> else<br> {<br> retval = TRUE;<br> (* toggle_function) (connection->timeouts, timeout, enabled, &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->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->failure_callback(connection->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't do<br>the timeouts=NULL part since we won'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'm not completely sure.<br> </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. 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>