_NTO_CHF_UNBLOCK

  1. Can someone please explain in detail what this flag affects.

I understand that if it is set, the server will be notified when the
client is about to unblock, and the server must reply, otherwise the
client stays blocked.

However, if it is cleared, does it mean (A) ONLY that the server will
not be notified of the client about to unblock, OR (B) IN ADDITION, the
client will be allowed to unblock without the server needing to do a reply.

  1. If the server does:
    rc=MsgReply()
    and (rc==ESRCH), it means: The thread indicated by rcvid doesn’t
    exist, or is no longer REPLY-blocked on the channel, or the connection
    is detached.

Could you explain what is the condition that “is no longer
REPLY-blocked” ? Is it the same as (B) above?

  1. The docs say that name_attach() will call ChannelCreate() with
    flags=0, however, it seems that the effect is that flags =
    _NTO_CHF_UNBLOCK. (See attached zip file)

  2. Is there a way that I can set a TimerTimeout before a MsgSend and be
    guaranteed that I will unblock if the timeout expires? It doesn’t seem
    logical to me to have to wait for the server to allow the client to
    unblock if the client’s timeout expires (or at least, we should have the
    option to enable/disable this feature).

In other words, if the client says “I need some data, but I’m only
willing to wait 2 seconds”, it seems illogical to me that the server can
decide to make the client wait more than 2 seconds before it decides to
let the client unblock and get the return code ETIMEDOUT. Even worse,
if the client has waited more than 2 seconds, and timed-out but it
doesn’t know, the server might decide to reply with the data (after more
than 2 seconds) and the client will never know that the timeout has
occured and that the data is more than 2 seconds old. Only after the
server has replied and gone back to its Receive() will it receive the
_PULSE_CODE_UNBLOCK. Of course this applies to a single-threaded server.


For all the above, please refer to attached zip file.

If you run server.exe, then run client.exe, the client will be
SEND-BLOCKED and timeout properly.

However, if you press a key on server to make it Receive, then client
will be REPLY-BLOCKED, timeout, but never return.

Then you have to press 2, followed by any key to let the server receive
the _PULSE_CODE_UNBLOCK and reply, in which case the client knows that
it has timed out.

If you press 1, you can make the server reply to the client, even if the
client has timed-out!! and the client does not get the ETIMEDOUT error
code!!

Thanks!
Alain.

Alain Achkar <js@simplytech.com> wrote:

  1. Can someone please explain in detail what this flag affects.

I understand that if it is set, the server will be notified when the
client is about to unblock, and the server must reply, otherwise the
client stays blocked.

However, if it is cleared, does it mean (A) ONLY that the server will
not be notified of the client about to unblock, OR (B) IN ADDITION, the
client will be allowed to unblock without the server needing to do a reply.

If the flag is not set, and the client needs to unblock (timeout, signal,
or thread cancel), then the client thread immediately unblocks AND the
server is not notified.

So, the server may continue to do work on the client’s behalf, and may
even try to reply to the (no longer blocked) client. If/when the server
does finally try to reply, the server will generally see a failure on
the MsgReply().

I say generally, because you can get into situations where bad things can
happen.

e.g.

Multi-threaded server, thread 1 is working on client request 1. Client
thread gets unblocked, handles signal, sends a new request (request 2) to
server. Server thread 2 gets this request, starts working. Server
thread 1 completes it work and replies to client with result of request 1.
So, now client request 2 gets the results of client request 1. Oops.

Or, single threaded server, client request 1 comes in, and is added to
a queue of pending requests (maybe waiting for data to come in). Unblock,
new request comes in, is a different request, gets added to a different
queue of not-yet-satisfied requests. Now, request 1 completes, reply
is done… and again request 2 gets (probably completely unrelated)
results of request 1.

Also, this can still happen even if the client dies/exits; the rcvid
can (and will) be re-used for the next client.

  1. If the server does:
    rc=MsgReply()
    and (rc==ESRCH), it means: The thread indicated by rcvid doesn’t
    exist, or is no longer REPLY-blocked on the channel, or the connection
    is detached.

Could you explain what is the condition that “is no longer
REPLY-blocked” ? Is it the same as (B) above?

This is condition B above.

  1. The docs say that name_attach() will call ChannelCreate() with
    flags=0, however, it seems that the effect is that flags =
    _NTO_CHF_UNBLOCK. (See attached zip file)

Where do the docs say that name_attach() will call ChannelCreate()
with flags=0? If the docs do say this, they are wrong. But, my
version of the documentation does not say any such thing. (It does say,
somewhat confusingly, that it “calls dispatch_create() and resmgr_attach()
to create a channel, however it doesn’t set any channel flags by itself.”
I will admit this description is not the clearest, and it should probably
be extended to say which channel flags are set by default by those pieces
as that information doesn’t seem to be covered.)

But, the example code also clearly shows the name_attach() server handling
_PULSE_CODE_UNBLOCK (as well as handling _PULSE_CODE_DISCONNECT, and with
comments about getting _PULSE_CODE_COIDDEATH and _PULSE_CODE_THREADDEATH)
which should be a further indications that name_attach() does set these
channel flags.

  1. Is there a way that I can set a TimerTimeout before a MsgSend and be
    guaranteed that I will unblock if the timeout expires? It doesn’t seem
    logical to me to have to wait for the server to allow the client to
    unblock if the client’s timeout expires (or at least, we should have the
    option to enable/disable this feature).

Choice 1: have the server properly and quickly handle the unblock
notification. See my above discussion of various race conditions
as to why I think this is a GOOD idea.

Choice 2: have the channel NOT set the UNBLOCK notification flag. This
is a bit trickier if you’re using name_attach(). Try:

dispatch_t *_dispatch_create( int chid, unsigned flags );

dispatch_t *dpp;
name_attach_t att;

chid = ChannelCreate( flags_you_want );
dpp = _dispatch_create( chid, 0 );
att = name_attach( dpp, “/my/name/here”, 0 );


In other words, if the client says “I need some data, but I’m only
willing to wait 2 seconds”, it seems illogical to me that the server can
decide to make the client wait more than 2 seconds before it decides to
let the client unblock and get the return code ETIMEDOUT. Even worse,
if the client has waited more than 2 seconds, and timed-out but it
doesn’t know, the server might decide to reply with the data (after more
than 2 seconds) and the client will never know that the timeout has
occured and that the data is more than 2 seconds old. Only after the
server has replied and gone back to its Receive() will it receive the
_PULSE_CODE_UNBLOCK. Of course this applies to a single-threaded server.


For all the above, please refer to attached zip file.

If you run server.exe, then run client.exe, the client will be
SEND-BLOCKED and timeout properly.

However, if you press a key on server to make it Receive, then client
will be REPLY-BLOCKED, timeout, but never return.

Then you have to press 2, followed by any key to let the server receive
the _PULSE_CODE_UNBLOCK and reply, in which case the client knows that
it has timed out.

If you press 1, you can make the server reply to the client, even if the
client has timed-out!! and the client does not get the ETIMEDOUT error
code!!

This is considered to be broken server design.

If the server is asking for unblock pulses (to properly clean up from
client signal/timeout) then the server is required to handle them in
an approrpriate and timely manner.

In some ways, if you think of that MsgSend() as calling into a library
that someone has supplied to you, it helps to understand some of this.
While in that library, the library code has decided to mask all signals,
then spend 10 minutes doing something. How can you escape? MsgSend()/
MsgReceive()/MsgReply() is a remote procedure call architecture. (No,
it isn’t the TCP/IP rpc protocol.) If you think of MsgSend() as calling
a function, where the implementation just happens to be in another process,
then this can help to understand things. If you call a local function,
it can not return for any amount of time – and, really, you can’t do
much about that. But, if it doesn’t, and it masks signals so that it
isn’t interrupted in this important operation, and never checks for
signals, that is bad design. Similarly, if you call a remote function,
and it doesn’t return in a reasonable time, and has asked for unblock
notification (equivalent of masking signals, to keep you in there), and
doesn’t handle the notification, this is bad design.

-David

David Gibbs
QNX Training Services
dagibbs@qnx.com

Thanks David! This helps clarify things for me and gives me some options
to choose from. I still have some questions/remarks though:

David Gibbs wrote:

Alain Achkar <> js@simplytech.com> > wrote:


3. The docs say that name_attach() will call ChannelCreate() with
flags=0, however, it seems that the effect is that flags =
_NTO_CHF_UNBLOCK. (See attached zip file)


Where do the docs say that name_attach() will call ChannelCreate()
with flags=0? If the docs do say this, they are wrong. But, my
version of the documentation does not say any such thing. (It does say,
somewhat confusingly, that it “calls dispatch_create() and resmgr_attach()
to create a channel, however it doesn’t set any channel flags by itself.”
I will admit this description is not the clearest, and it should probably
be extended to say which channel flags are set by default by those pieces
as that information doesn’t seem to be covered.)

Sorry, my mistake. Since the docs say “to create a channel”, I made the
wrong assumption that ChannelCreate() will be called. And since “it
doesn’t set any flag”, I assumed that _NTO_CHF_UNBLOCK will be cleared.

But, the example code also clearly shows the name_attach() server handling
_PULSE_CODE_UNBLOCK (as well as handling _PULSE_CODE_DISCONNECT, and with
comments about getting _PULSE_CODE_COIDDEATH and _PULSE_CODE_THREADDEATH)
which should be a further indications that name_attach() does set these
channel flags.

What makes this example confusing is that the _PULSE_CODE_UNBLOCK
section never gets called when the client times out (as can be
demonstrated by the attached name_attach2.c, which is the same example
with 'printf’s added). The only way to execute that section is to
modify the code (as in my previous post attachment) so that the server
goes back to the MsgReceive() while the client is REPLY-blocked and
times out. Only then will the pulse be received.

Also, [maybe I’m doing something wrong?] name_attach() doesn’t seem to
be sending an _IO_CONNECT message, as can be seen with the printf in the
same attachment.

  1. Is there a way that I can set a TimerTimeout before a MsgSend and be
    guaranteed that I will unblock if the timeout expires? It doesn’t seem
    logical to me to have to wait for the server to allow the client to
    unblock if the client’s timeout expires (or at least, we should have the
    option to enable/disable this feature).


    Choice 1: have the server properly and quickly handle the unblock
    notification. See my above discussion of various race conditions
    as to why I think this is a GOOD idea.

Choice 2: have the channel NOT set the UNBLOCK notification flag. This
is a bit trickier if you’re using name_attach().

So, if I don’t have control over the server (someone else wrote it - QNX
or a third party), then I’m out-of-luck ? :slight_smile:

Try:

dispatch_t *_dispatch_create( int chid, unsigned flags );

It worked! :slight_smile:

I looked everwhere for this funcion, but could not find it. Is it
undocumented? If so, what is the ‘flags’ parameter ?

The line:
dpp = _dispatch_create( chid, 0 );
is giving:
server.c:66: warning: assignment makes pointer from integer without a
cast.

Can this be safely ignored?

=========================================================================

I know that readcond() was mentioned but its resolution is 1/10 of a
second, so I would still like to concentrate on the following and see if
I’m doing anything wrong in tst1.c attached. You can run it by typing:

tst1 timeout_ms

where timeout_ms is the time in milliseconds that you would like to wait
for the read() function to return. Type any characters to stop the
read() from timing out, or do not type any characters to let it time out.

If I only set:
flags = _NTO_TIMEOUT_REPLY ;
then, sometimes at random, the read() will not return.

tst1 is REPLY-blocked on devc-pty, however, devc-pty is RECEIVE-blocked!
Here’s my pidin:
pid tid name prio STATE Blocked
147467 1 sbin/devc-pty 10r RECEIVE 1
1261589 1 ./tst1.exe 10r REPLY 147467

If, however, I set:
flags = _NTO_TIMEOUT_REPLY | _NTO_TIMEOUT_SEND ;
then it works (times out everytime).

However, when it times out, it does not return ETIMEDOUT, it returns EINTR.

=========================================================================

Alain.

Alain Achkar <js@simplytech.com> wrote:

This is a multi-part message in MIME format.
--------------020103060400030809080504
Content-Type: text/plain; charset=us-ascii; format=flowed
Content-Transfer-Encoding: 7bit

Thanks David! This helps clarify things for me and gives me some options
to choose from. I still have some questions/remarks though:

David Gibbs wrote:
Alain Achkar <> js@simplytech.com> > wrote:


3. The docs say that name_attach() will call ChannelCreate() with
flags=0, however, it seems that the effect is that flags =
_NTO_CHF_UNBLOCK. (See attached zip file)


Where do the docs say that name_attach() will call ChannelCreate()
with flags=0? If the docs do say this, they are wrong. But, my
version of the documentation does not say any such thing. (It does say,
somewhat confusingly, that it “calls dispatch_create() and resmgr_attach()
to create a channel, however it doesn’t set any channel flags by itself.”
I will admit this description is not the clearest, and it should probably
be extended to say which channel flags are set by default by those pieces
as that information doesn’t seem to be covered.)


Sorry, my mistake. Since the docs say “to create a channel”, I made the
wrong assumption that ChannelCreate() will be called. And since “it
doesn’t set any flag”, I assumed that _NTO_CHF_UNBLOCK will be cleared.

As I said, the docs are quite confusing there – you came to a very
reasonable conclusion from what they said. I’ve issued a PR to have
better information put in there.

But, the example code also clearly shows the name_attach() server handling
_PULSE_CODE_UNBLOCK (as well as handling _PULSE_CODE_DISCONNECT, and with
comments about getting _PULSE_CODE_COIDDEATH and _PULSE_CODE_THREADDEATH)
which should be a further indications that name_attach() does set these
channel flags.

What makes this example confusing is that the _PULSE_CODE_UNBLOCK
section never gets called when the client times out (as can be
demonstrated by the attached name_attach2.c, which is the same example
with 'printf’s added). The only way to execute that section is to
modify the code (as in my previous post attachment) so that the server
goes back to the MsgReceive() while the client is REPLY-blocked and
times out. Only then will the pulse be received.

This is intentional.

You can’t receive a pulse unless you go back to the MsgReceive(). If
you take a while, the client “times out”, the unblock pulse is queued,
then without calling MsgReceive(), you unblock the client (by replying,
for example), then the unblock pulse is removed (not delivered) because
it is no longer needed – the client has already been unblocked, so
there is no longer any need to tell the server it needs to unblock the
client. (Also, delivering it could cause a race condition… e.g. if
the client is unblocked, sets it’s priority higher, then sends to the
server again. The new send would arrive ahead of the (old) unblock
pulse, the server would get the new request, then the unblock pulse,
and assume it was an unblock for the new message, not the old.)


Also, [maybe I’m doing something wrong?] name_attach() doesn’t seem to
be sending an _IO_CONNECT message, as can be seen with the printf in the
same attachment.

sigh

Do I have to talk about this one?

Ok… I’m not sure what the “proper” behaviour is at the moment.

See, it used to be that name_attach()/name_open() only worked locally
(on the same node). And no _IO_CONNECTs were sent. Then, the ability
to do global (accross networks) attachs/open was added, but to resolve
the server accross the network required a message to be sent, so an
_IO_CONNECT message was sent by name_open(). But, this broke existing
applications. So, there was an argument about not breaking existing
applications vs being consistent in the network vs local case. And
I don’t know how the argument finished. So, I don’t know what the
“right” behaviour is at the moment, or whether the docs are right or
wrong, or whether I need to PR something (again).

Probably more than you wanted to know, but there you go.

  1. Is there a way that I can set a TimerTimeout before a MsgSend and be
    guaranteed that I will unblock if the timeout expires? It doesn’t seem
    logical to me to have to wait for the server to allow the client to
    unblock if the client’s timeout expires (or at least, we should have the
    option to enable/disable this feature).


    Choice 1: have the server properly and quickly handle the unblock
    notification. See my above discussion of various race conditions
    as to why I think this is a GOOD idea.

Choice 2: have the channel NOT set the UNBLOCK notification flag. This
is a bit trickier if you’re using name_attach().

So, if I don’t have control over the server (someone else wrote it - QNX
or a third party), then I’m out-of-luck ? > :slight_smile:

Yup.

Or, at least, you HOPE they handle the unblock notification properly,
and bug them to fix any bugs you find with it.

Try:

dispatch_t *_dispatch_create( int chid, unsigned flags );


It worked! > :slight_smile:

I looked everwhere for this funcion, but could not find it. Is it
undocumented? If so, what is the ‘flags’ parameter ?

It is not documented. I thought I said it wasn’t documented. If
not, I should have said it was undocumented.

The line:
dpp = _dispatch_create( chid, 0 );
is giving:
server.c:66: warning: assignment makes pointer from integer without a
cast.

Did you prototype it? If you didn’t, it will default to returning
an int, and when you assign it to a dispatch_t *, it will give that
warning.

Can this be safely ignored?

Better to fix it.

Currently, I think that an int and a pointer are the same on all
our platforms – but that may not always be true.

I know that readcond() was mentioned but its resolution is 1/10 of a
second, so I would still like to concentrate on the following and see if
I’m doing anything wrong in tst1.c attached. You can run it by typing:

tst1 timeout_ms

where timeout_ms is the time in milliseconds that you would like to wait
for the read() function to return. Type any characters to stop the
read() from timing out, or do not type any characters to let it time out.

If I only set:
flags = _NTO_TIMEOUT_REPLY ;
then, sometimes at random, the read() will not return.

tst1 is REPLY-blocked on devc-pty, however, devc-pty is RECEIVE-blocked!

That might be a bug. Just spent a while looking through the kernel
trying to figure out what is happening. Not sure what is happening.

If, however, I set:
flags = _NTO_TIMEOUT_REPLY | _NTO_TIMEOUT_SEND ;
then it works (times out everytime).

And, you want to set this anyway. If your time expires while
you are SEND blocked (before the server receives), you want to
timeout immediately, so probably want to include the _NTO_TIMEOUT_SEND.

(What I speculate is happening, though I’m not sure, is that the
tiemout happens while you are SEND block, you aren’t REPLY blocked
at that point, so don’t timeout, and that the expired timeout for
REPLY is not caught on the transition to REPLY.)

However, when it times out, it does not return ETIMEDOUT, it returns EINTR.

Unfortunate, but yes. I think I may have mentioned this, but the
event that the server gets does not have room to tell the server
why you need to unblock (e.g. cancel, timeout, or signal), so the
server can’t do the “right” MsgError(), and just chooses EINTR.

The documentation should probably be updated to reflect this.

-David

David Gibbs
QNX Training Services
dagibbs@qnx.com

Also, [maybe I’m doing something wrong?] name_attach() doesn’t seem to
be sending an _IO_CONNECT message, as can be seen with the printf in the
same attachment.

sigh

Do I have to talk about this one?

Ok… I’m not sure what the “proper” behaviour is at the moment.

See, it used to be that name_attach()/name_open() only worked locally
(on the same node). And no _IO_CONNECTs were sent. Then, the ability
to do global (accross networks) attachs/open was added, but to resolve
the server accross the network required a message to be sent, so an
_IO_CONNECT message was sent by name_open(). But, this broke existing
applications. So, there was an argument about not breaking existing
applications vs being consistent in the network vs local case. And
I don’t know how the argument finished. So, I don’t know what the
“right” behaviour is at the moment, or whether the docs are right or

I believe the argument ends up “being consistent in network/local case”.
However, the current release’s behavior is:

  1. if “gns” (The “global name services” manager) is running, both
    network/local case would have an _IO_CONNECT sent to server

  2. if “gns” is NOT running, (You can only attach local in this case)
    no _IO_CONNECT send out.

The 2) is current treat as an Bug, there is already an PR opened
against this.

-Xiaodan Tang
ES, QSS