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
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