Can recvfrom() on a non-blocking socket block?

On QNX 6.2: I have two FIFO-scheduled threads of equal priority,
one of which attempts to do a recvfrom() on a non-blocking socket. It
appears that the thread calling recvfrom() gets bumped from the
runqueue and preempted by the other thread–even though the socket is
non-blocking.

Erm… should I be surprised by this, or is this ‘normal’? Is there a
different way (e.g., select()) of doing a non-blocking socket read that
doesn’t cause my thread to lose his position in the runqueue?

TIA,

  • Dave

David Wolfe <da5id@luvspamwolfe.name> wrote:

On QNX 6.2: I have two FIFO-scheduled threads of equal priority,
one of which attempts to do a recvfrom() on a non-blocking socket. It
appears that the thread calling recvfrom() gets bumped from the
runqueue and preempted by the other thread–even though the socket is
non-blocking.

Erm… should I be surprised by this, or is this ‘normal’? Is there a
different way (e.g., select()) of doing a non-blocking socket read that
doesn’t cause my thread to lose his position in the runqueue?

Even though the SOCKET IO won’t block, the process has to send a message
to the TCP/IP stack to determine IF there is any data to receive. If
there is is none, the stack should immediately return.

Bottom line, yes, it is working correctly.

It appears that the thread calling recvfrom() gets bumped from the
runqueue and preempted by the other thread–even though the socket
is non-blocking.

Erm… should I be surprised by this…

Even though the SOCKET IO won’t block, the process has to send a
message to the TCP/IP stack to determine IF there is any data to
receive. If there is is none, the stack should immediately return.

Bottom line, yes, it is working correctly.

Thanks for the response! Yes, that makes total sense in the context of
QNX’s message-passing ‘guts’ (which I’ve so far been insulated from). I
guess I can set the priority of io-net anywhere I want, but… the
thread sending the message (via recvfrom()) will still get bumped, and
the other same-priority thread will run before the first one gets the
packet?

I did a quick experiment with select() and it appears to not bump the
caller out of his slot in the runqueue. What does this imply about the
way the select() call works ‘under the covers’ versus recvfrom()? If I
want non-blocking and non-preemption by same-priority peers, is select()
the way to go? Or… is this just A Bad Idea t.m. (I’m asking myself
right now why these two threads are the same priority, anyway…)

David Wolfe <da5id@luvspamwolfe.name> wrote:

Thanks for the response! Yes, that makes total sense in the context of
QNX’s message-passing ‘guts’ (which I’ve so far been insulated from). I
guess I can set the priority of io-net anywhere I want, but… the
thread sending the message (via recvfrom()) will still get bumped, and
the other same-priority thread will run before the first one gets the
packet?

I did a quick experiment with select() and it appears to not bump the
caller out of his slot in the runqueue. What does this imply about the
way the select() call works ‘under the covers’ versus recvfrom()? If I
want non-blocking and non-preemption by same-priority peers, is select()
the way to go? Or… is this just A Bad Idea t.m. (I’m asking myself
right now why these two threads are the same priority, anyway…)

I would have bet my buttons that select() also sent a mesasge to some
resourse manager. I wonder if it is just blocking at a less time
critical time for you.

BTW, what I think you want to do is to use semaphores. The FIFO method
is not reliable on an SMP system.


Bill Caroselli – Q-TPS Consulting
1-(626) 824-7983
qtps@earthlink.net

I did a quick experiment with select() and it appears to not bump
the caller out of his slot in the runqueue…

I would have bet my buttons that select() also sent a mesasge to some
resourse manager…

BTW, what I think you want to do is to use semaphores. The FIFO
method is not reliable on an SMP system.

Yeah, that may be what we wind up doing. But I’m still trying to wrap
my mind around what’s going on. Going back to recvfrom(), say I have
the following:

MyThread A @ Priority 12 (SCHED_FIFO)
MyThread B @ Priority 12 (SCHED_FIFO)
io-net @ Priority 10 (SCHED_OTHER(?))

If ThreadA calls recvfrom(), he–behind the scenes–sends a message to
io-net, right? If I’ve understood correctly how QNX works, this will
momentarily bump io-net’s priority up to 12. From what I can tell,
Thread A becomes REPLY blocked(?), and io-net (who has been sitting
around RECEIVE blocked, waiting for client messages) gets moved to the
tail of the runqueue for Priority 12 threads. Meanwhile, the OS had to
pick somebody to run. So he picked ThreadB, who was next in line in the
Priority 12 queue.

ThreadB runs until he yields(), which bumps him to the end of the line,
and then io-net finally gets a crack at answering ThreadA’s message.
After he replies, he becomes RECEIVE blocked again, at his original
priority. Thread A, at long last, receives io-net’s reply and wakes up.
Is this analysis more-or-less accurate? Thread A doesn’t lose his
position in the priority queue, but he remains blocked because io-net
is stuck behind ThreadB? (I think that was the source of my original
confusion; it appeared that recvfrom() was doing the equivalent of a
sched_yield(), allowing B to run.)

David Wolfe <da5id@luvspamwolfe.name> wrote:

Yeah, that may be what we wind up doing. But I’m still trying to wrap
my mind around what’s going on. Going back to recvfrom(), say I have
the following:

MyThread A @ Priority 12 (SCHED_FIFO)
MyThread B @ Priority 12 (SCHED_FIFO)
io-net @ Priority 10 (SCHED_OTHER(?))

If ThreadA calls recvfrom(), he–behind the scenes–sends a message to
io-net, right? If I’ve understood correctly how QNX works, this will
momentarily bump io-net’s priority up to 12. From what I can tell,
Thread A becomes REPLY blocked(?), and io-net (who has been sitting
around RECEIVE blocked, waiting for client messages) gets moved to the
tail of the runqueue for Priority 12 threads. Meanwhile, the OS had to
pick somebody to run. So he picked ThreadB, who was next in line in the
Priority 12 queue.

ThreadB runs until he yields(), which bumps him to the end of the line,
and then io-net finally gets a crack at answering ThreadA’s message.
After he replies, he becomes RECEIVE blocked again, at his original
priority. Thread A, at long last, receives io-net’s reply and wakes up.
Is this analysis more-or-less accurate? Thread A doesn’t lose his
position in the priority queue, but he remains blocked because io-net
is stuck behind ThreadB? (I think that was the source of my original
confusion; it appeared that recvfrom() was doing the equivalent of a
sched_yield(), allowing B to run.)

There are two problems with the way that you described it. The first
is trivial. When io-net finishes the request for TreadA it doesn’t go
back to priority 10 (it can, but I’m sure it doesn’t). There is no
purpose to it. The priority doesn’t matter in a thread that is NOT
running, AND when it receives it’s next request ti will re-adjust
itself back to that priority.

The second issue may be what is tripping you up. When a process blocks
it doesn not immediately get put back in the end of the READY queue
for that priority, it is BLOCKED. At the time that it is made READY
again, then it put’s itself back at the end of the READY queue.

So, it’s not that it lose it’s place in line (as you put it). It never
had one.


Bill Caroselli – Q-TPS Consulting
1-(626) 824-7983
qtps@earthlink.net

There are two problems with the way that you described it. The first
is trivial. When io-net finishes the request for ThreadA it doesn’t
go back to priority 10 (it can, but I’m sure it doesn’t). There is no
purpose to it. The priority doesn’t matter in a thread that is NOT
running, AND when it receives it’s next request ti will re-adjust
itself back to that priority.

Thanks for clarifying. That makes sense.

The second issue may be what is tripping you up. When a process
blocks it does not immediately get put back in the end of the
READY queue for that priority, it is BLOCKED. At the time that it
is made READY again, then it put’s itself back at the end of the
READY queue.

Oops. I was stumbling to speak ‘spec-ese’, but I haven’t quite gotten
the lingo down. :blush: I’m trying to understand things in terms of the
conceptual model described at:

http://www.opengroup.org/onlinepubs/007908799/xsh/realtime.html/#tag_000_008_004
_001


I admit I’m still a little confused by the wording of the spec. But
something you said helped:

When a process
blocks it does not immediately get put back in the end of the
READY queue for that priority, it is BLOCKED.

I was failing to make a distinction between blocking and preemption by a
higher-priority process. If you make a blocking call (e.g., recvfrom())
you are going to get yanked from the processor and put in a wait
queue. When you are made READY again, you’ll wind up at the tail
end of the ready queue for your priority. If you get preempted by a
higher-priority process, however, you just get put back onto the
head of your priority class’ ready queue. You don’t ‘lose your place’,
since you never gave up the processor. But you always lose your place
in the READY queue when you block, since you (eventually) wind up on its
tail.

I think I get it now–thanks. One other question comes to mind,
though: is there some way to get a list of QNX functions that are
inherently blocking? How do you know whether sprintf(), for example,
sends a message to some QNX service or just ‘does the deal’?

“David Wolfe” <da5id@LUVSPAMwolfe.name> wrote in message
news:b46fub$qpm$1@inn.qnx.com

There are two problems with the way that you described it. The first

I think I get it now–thanks. One other question comes to mind,
though: is there some way to get a list of QNX functions that are
inherently blocking? How do you know whether sprintf(), for example,
sends a message to some QNX service or just ‘does the deal’?

With some experience you’ll ‘get the feeling’. Basically, if a function
sounds like it might need services of an external process, chances are it
winds up doing MsgSend() inside and then sits blocked, waiting for a reply.
The sprintf() for example should not need any external services since all it
does is format the string. The printf() and fprintf() however will need to
send message to a corresponding resource manager (which could be devc-con or
devc-ser8250 or whatever is your console). The only exception is when the
external entity is the kernel itself (e.g., creation of a mutex, etc) - you
don’t send messages to the kernel.

– igor

David Wolfe <da5id@luvspamwolfe.name> wrote:

I think I get it now–thanks. One other question comes to mind,
though: is there some way to get a list of QNX functions that are
inherently blocking? How do you know whether sprintf(), for example,
sends a message to some QNX service or just ‘does the deal’?

There is no such list that I know of. BUT, each library function
has a “safety table” at the bottom, and any function that is listed
as safe to use in an Interrupt handler can be depended on to be
non-blocking. (There may be others, and there are some that
“might” be non-blocking or might not, depending on the current
state of the library.)

But, that will give you a good general guess at it. Beyond that, if
you have a few specific functions that you can’t figure out, you can
take a look at cvs.qnx.com – it is a (6.1) copy of the library source,
and that would give you a good idea of whether or not a particular
function would make a blocking call, and if that still doesn’t work,
you can always post a list here and ask.

-David

QNX Training Services
http://www.qnx.com/support/training/
Please followup in this newsgroup if you have further questions.