On Apr 26, 2010, at 1:45 PM, Angus Salkeld wrote:
Hi
In looking to improve the usability of libqb functions (mainly ipc client & server
functions).
I started looking at the way glib & dbus do it.
GMainLoop * g_main_loop_new (GMainContext *context,
gboolean is_running);
GMainContext * g_main_context_new (void);
GSource * g_timeout_source_new (guint interval);
glib describes these returned types as "opaque". You can't do anything to
them directly.
DBusConnection * dbus_connection_open (const char *address, DBusError *error);
dbus says: "All fields are private."
So the returned type has no real value to the user - it is just a pointer you have to
use.
Both glib and dbus provide reference and dereference functions to prevent these pointers
from been freed by other code (in another thread). They use atomic inc & dec
functions.
The current API of corosync is "inherited" from the AIS API.
This looks like:
a_handle_t handle;
res = something_create (args ..., &handle);
...
res = something_get (handle, ...);
...
something_destroy (handle);
Here handles are like file handles to represent an object. Every time you
open/create an "object", it has a reference count incremented.
So both take care of reference counting but if you have an old pointer/handle
to a destroyed object then the pointer method would result in a crash if you
dereferenced it where as the handle method would result in a "bad handle"
error code.
Only true if you're using stack variables.
Once you start allocating memory to store the handles in, I'm pretty sure you'll
hit the same type of problems.
Which is better?.
I think it mostly depends on the lifespan of these things.
I get the impression that handles aren't really supposed to be used outside the
function that opened/created it.
By contrast Gmainloop and friends last almost forever.
1)
The pointer API seems to be a little more friendly/obvious to me.
Also it is typed in that you will get a compiler error if you pass GSource*
into a function expecting a GMainLoop* argument (although this could be done with handles
too).
Typing is definitely a plus.
2)
The handle seems a little safer if you have old/stale references.
3)
It is also good to be "like the others" in terms of familiarity to developers
(easy of use).
I'd not worry _too_ much about this.
What's best in this specific instance (if there is a "best") probably takes
priority.
Are there any other arguments for either type of API?
If I had to choose, I'd say glib-style.
But thats more a personal preference than anything else.
Another question is the way return codes are returned:
1)
APointer* obj;
SomeStatus ret;
obj = xyz_create("something", &ret);
if (!obj) {
xyz_print_error(ret);
return;
}
2)
a_handle_t handle;
int ret;
ret = xyz_create ("something", &handle);
if (ret != 0) {
perror (ret);
return;
}
Any opinions on these?
1) certainly makes it harder to forget/ignore return codes (and therefor gets my vote)
Basically the question is:
Do we follow posix API or libraries like glib/libevent/dbus?
I am leaning towards the "glib/libevent/dbus" style API as libqb
is at a similar layer. We are providing higher layer functionality
on top of a posix API.
-Angus