<div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div>Hi sd-bus-ers!</div><div><br></div><div>Quick question: How can I process a method call on service side in a different thread, without creating race condition?</div><div><br></div><div>Longer version:<br></div><div><br></div><div>In sdbus-c++, we are working on server-side asynchronous method call support.<br></div><div><br></div>In sd-bus, a service handles D-Bus method calls via sd_bus_message_handler_t callback that is registered during object vtable registration. The callback receives sd_bus_message* as the first parameter (among others), which is the method call message. In a typical implementation, this method call is served synchronously (D-Bus method parameters are deserialized from the message, an operation is executed, and either method reply or method error, depending on the condition, is sent back) and the callback returns execution to sd-bus. Standard stuff so far.<div><br></div><div>Now, I would like to handle the method call asynchronously, in a thread pool. So a typical approach would be to increment ref count of sd_bus_message and push the 
 sd_bus_message* in a queue. It would then be popped by one of worker threads and processed -- method parameters are deserialized, method logic is executed, and either method reply or method error is created and sent back, and sd_bus_message* ref count is decremented. Now, sending back the reply or an error is thread-safe in my implementation, I don't have an issue with that. The problem that I want to discuss is the method call sd_bus_message instance. I cannot simply forward a pointer to it to a separate thread, because of it's non-atomic ref count handling, which is the source of race condition (hopefully this is the only data race condition here). It's manipulated by both the D-Bus loop thread (which decrements ref count after 
sd_bus_message_handler_t

returns) and the worker thread concurrently (which also decrements ref count after it has handled the method call).<br></div><div><br></div><div>I see three potential solutions now:</div><div><br></div><div>1. In 
sd_bus_message_handler, create a deep copy of the method call sd_bus_message via sd_bus_message_copy(). And pass a pointer to this copy to a worker thread. This is very straight-forward and simple, it solves the race condition, but introduces a performance cost of copying (I don't know how big this cost is, perhaps it's rather negligible).</div><div><br></div><div>2.  Don't pass the 
sd_bus_message* to the worker thread. 
In 
sd_bus_message_handler, rather deserialize all arguments, create (empty) method reply message, and move these to the worker thread. The worker thread executes the logic and serializes results to that reply message, and sends it back. The problem here is that we have to create a method reply or method error before the fact (before executing method logic), which in case of method error is impossible because we don't know possible error name and message beforehand.</div><div><br></div><div>3. Solution on sd-bus side :-) which is to make sd_bus_message ref count handling thread-safe (atomic), just like one for sd_bus. This avoids the need for deep copy. What do you think? Anyway, we'd still have to come up with a solution now, based on already releases sd-bus versions.<br></div><div><br></div><div>So the only feasible solution for now seems to be #1 (while #3 could also be a sd-bus improvement for the future). Do you agree that this is the good way along the lines of sd-bus design principles, or are there more options I'm unaware of?</div><div><br></div><div>Thank you for your constructive comments, and sorry for long elaboration :) I wanted to be clear...<br></div><div><br></div><div>Cheers,</div><div>Stanislav.</div><div><br></div></div></div></div></div>