Quantcast
Viewing all articles
Browse latest Browse all 5648

still trying to get proton messenger to behave properly asynchronously

Hey all,
I've been able to get messenger to behave fairly sensibly in a
non-blocking way, but what I've yet to achieve is getting it to behave
in a properly "asynchronous" event-driven way where I fire up a looping
"notifier" after everything is initialised and the notifier calls the
"callbacks", you know, the usual event driven pattern.

For my send-async code I've got a "main_loop" function that performs the
guts of the work, the key bits look like this:

#define SENT_MESSAGE 0
#define STOPPING 1

void main_loop(void *arg) {
printf(" *** main_loop ***\n");

int err = pn_messenger_work(messenger, 0); // Sends any outstanding
messages queued for messenger.
int pending = pn_messenger_outgoing(messenger); // Get the number
of pending messages in the outgoing message queue.

printf("err = %d\n", err);
printf("pending = %d\n", pending);

if (state == SENT_MESSAGE & !pending) {
printf("calling stop\n");
pn_message_free(message); // Release message.
pn_messenger_stop(messenger);
state = STOPPING;
} else if (state == STOPPING & !err) {
printf("exiting\n");
pn_messenger_free(messenger);
exit(0);

in the main method I set messenger to non-blocking, create and send the
message and set state to SENT_MESSAGE

when I have a "notifier" loop like the following:

while (1) {
main_loop(NULL);

struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = 16667;
select(0, NULL, NULL, NULL, 똩麢);

The approach above works fine and reaches the final state and exits, but
It's not really what I want as it's essentially a busy-wait loop albeit
with a 16.7 ms delay. What I *really* want is for the main notifier
event loop to block until activity is happening.

I tried:

while (1) {
pn_driver_wait(messenger->driver, -1); // Block indefinitely until
there has been socket activity.
main_loop(NULL);

But that doesn't even compile (error: dereferencing pointer to
incomplete type) I guess pn_messenger_t isn't externally visible outside
messenger.c so I can't access the driver instance?

If I do:

while (1) {
pn_messenger_work(messenger, -1); // Block indefinitely until there
has been socket activity.
main_loop(NULL);

That "kind of" works, but it doesn't get as far as the exit state (the
last err value is -7), so there's socket activity that I'm missing I think.

In any case I *really* don't like having to do a blocking call to
pn_messenger_work() just to do the select/poll call that I really want
to do.

If I'm honest I don't *think* messenger is currently entirely geared up
for asynchronous behaviour despite the ability to put it in non-blocking
mode. What I mean is that the heart of many of the calls is
pn_messenger_tsync, which is called in blocking and non-blocking modes
and that's calling pn_driver_wait, potentially in a loop even in
non-blocking mode, so even if my notifier could do a simple block on
pn_driver_wait I'd still by calling poll multiple times - once blocking
in my notifier waiting for activity and then non-blocking when I do.
pn_messenger_work(messenger, 0); // Sends any outstanding messages
queued for messenger.

Even when it is working well I'm suspecting that the loop will be
causing more calls to main_loop than really desirable as it'll trigger
on all socket activity not just the send - perhaps that's necessary
because of the AMQP handshaking, but it doesn't "feel" especially
efficient, but I'm certainly far from an expert about the guts of
messenger - it made my head explode :-)

I guess that most uses to date have been for traditional blocking
scenarios, but I'm thinking that in the future a more asynchronous
approach is likely to become important - what I mean is that as the
number of processor cores increases I suspect that asynchronous
approaches like Grand Central Dispatch
http://en.wikipedia.org/wiki/Grand_Central_Dispatch will probably scale
better across large numbers of cores, so it might be good to have an
efficient asynchronous programming model for proton.

Am I roughly on the right track? Any ideas how to make what I'm trying
to do a little neater?

At this stage I'm trying things out and trying to educate myself, so if
there are limitations it's not necessarily a huge deal, but it might be
a useful point for further conversation on asynchronous behaviour -
anyone else musing over this?

Best regards,
Frase

Viewing all articles
Browse latest Browse all 5648

Trending Articles