Hi Mickey, > as you might know I'm working on the dbus API for the forthcoming phone > server. There's a conceptual disagreement about whether to use a mainly > synchronous or mainly asynchronous API, e.g. would you rather call a method > that returns the results or call a method that triggers a signal that will > eventually come. > > The synchronous API may be simpler to follow, however the asynchronous API is > more natural since both the modem and the UI are basically event-based > models. > > However, it looks like 90% of the existing dbus APIs are using the > synchronous > approach. > > This decision is quite important as it lays out the base for the phone server > architecture and possibly eventually a reimplementation of the gsm 0707 > backend.
the first thing that you have to understand is that D-Bus in itself is fully asynchron. The illusion that you have the synchronous calls comes from the fact that methods can behave like function, but that is not how D-Bus actually works. A method call is a D-Bus message. Nothing more and nothing less. A method message can be answered by a reply message or an error message or by now message at all. This return message can come at any time. However in case you use synchronous/blocking functions from the D-Bus API this will look like a synchronous approach, but it isn't. What you are doing is that have the mainloop waiting for the response. This is feasible for command line utilities or in cases where the order of method calls are required, but in most cases you wanna use asynchronous method calls. Especially within UI applications, because otherwise you might block the mainloop of the application. It is really important to understand this difference. Using D-Bus in a synchronous is wrong most of the times. The D-Bus message calls also imply the concept of timeouts. In the case a method is not marked/annotated as no-reply, it has to be answered with an error or a reply. Otherwise the the system/session bus will generate a timeout event and return with an error. The timeout of a message call is flexible and the caller can set this timeout. In most cases the default value works perfectly fine, but in some other cases it might be a good idea to extend the timeout. Mainly when you deal with hardware and know it can take some extra time before you can generate the reply message. Also keep in mind that during the D-Bus message callbacks you are blocking the mainloop. Compare it to code that is handled inside an interrupt. You wanna do this as quick as possible. Otherwise your intend is to use it asynchron, but the server/service makes it synchron. That said, signals are also only messages. The only exception is that they don't imply a return message and that they are broadcasted. Now to your question. Using D-Bus method calls is perfectly fine and the right approach to do many things. However looking from the exporting perspective is always wrong. Look from the user perspective and define the API that a user aka UI application (or multiple) really needs. This means that any kind of polling is wrong. No matter what, because waking up for status changed detection is only draining the battery. So if any state or value etc. changes that the UI needs to be informed of, send a signal. This allows application to listen to events without even having to deal with the whole picture. For example if you have a nice applet that only shows the network name, it will on startup us a method call (GetNetwork for example) to get the initial network name and display it. After that it will only listen to a signal (NetworkChanged for example) to update its display. I prefer the idea of totally stupid UIs whenever possible. Move the hard work into the daemons. In conjunction with this example you might have a method to change the network (SetNetwork for example). This will be called from a total different application (network settings) and you only have to make sure that in the end it emits a signal when the network change has taken place so the stupid network name display UI can update its information. In some cases you wanna use method that might take longer and involve multiple values to return. In this case you have a method that triggers a certain action and all results are returned as signals. This is a good idea for starting a scan operation or something that really takes a long time. There are multiple ways to get this kind of task done. My advise is too keep in mind if the reported information can be used by other applications at the same time. So some times you have to indicate that an operation started and when it ends. Besides this discussion it is important to design the API in a way it is friendly for the UI and even more important efficient. Round-trips to the D-Bus should be avoided whenever possible. The best way to do this is to use dictionaries as return values. Don't use structs. They are too inflexible and painful to handle. The dictionaries can be easily mapped to native types of the binding, while for the structs you have to deal with complex marshaling or iterate of the message parameters. Both is painful and makes code really complex and hard to understand. Also the use of integer constants is a bad idea. Simply use string constants. For example for the network status use "unknown", "available" and so on. The use of integer constants leaves room for error and doing it from higher languages like Python or Perl is painful. Using strings is much more easier there. Not to mention that debugging becomes really easy if you have plain strings. Another small tip from me that you might not wanna make the API stable and frozen before you actually have written the UI. When you start writing the UI or any kind of application using that API you see how good it really is. A lot things look good when you design it, but when you start using it, it becomes more and more problematic. Make it easy for the UI should be the first rule of business. Don't look too much at other D-Bus APIs. Especially the ones that are around for some time. To be quite honest, most of the early adopters had no idea what they were doing at that time. And I am happily include me to that list. We learned from our mistakes and have now a solid ground for D-Bus API design, but we still live with mistakes we made. Once you understand the full potential of D-Bus and how to use it properly it is powerful. If you try to apply stupid C/C++/Python/OO etc. API to it you make your life unnecessary hard. With D-Bus you can play a lot of nice tricks that allows you the best separation between UI and daemon code. One example might be the agent concept to allow proper callbacks into UI code. If you want me to, I can have a full review of your current API. I only just had a quick look, but there are a lot of things that can be simplified. Regards Marcel

