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, &timeout);
  }

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

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to