Tony <mts.spb.suxx@mail.ru> wrote:
On Wed, 04 May 2005 00:44:56 +0400, David Gibbs <> dagibbs@qnx.com> > wrote:
My first choice would be to use 2 queues, one for the high priority
process, and one for the low priority process.
This kills the very idea of mqueue for me. Why not just receive and
react to the messages directly then?!
Sure, why not? (I’m actually going to suggest it…)
This does not scale well if one wants something more intricate than just
two senders and two levels of priority for the messages.
Well, have one queue per sender doens’t scale very well, but using
QNX Send/Receive/Reply does scale reasonably well for multiple senders
and priorities. And, if you don’t mind a client being blocked until
they reach the top of the priority list, it also isn’t that hard to
design/implement. But, if you want to dequeue and reply, that means
implementing a priority-list queue in the driver. Not too difficult,
quite scalable, but may be work you don’t need/want to do. (But, it
does give you the most custom and configurable choice; and probably
the most CPU and latency efficient method.)
The main advantage of the message queues is the ability to have someone
else manage an “in-transit” message, while you’re off doing something
else.
Exactly!
I want to isolate the receiving process from any details of how many are
the senders there, how many are the priority levels of the messages. Let
it read just one queue and keep the hardware working.
The queue is up to 6464 bytes.
That is a very small queue. The overhead of mqueue to manage 64 entries
of 64 bytes is pretty hefty.
OK.
Does it track the actual data length in the entry? If the entry slot is
3264 and I put there just a 64-bytes message - how much memory will be
copyed during the mq_send() and mq_receive()?
It does track the length. In that case, just 64 bytes will be copied
on both mq_send and mq_receive. Note, though, if the queue entry size
is 3264 bytes, and the sender did an mq_send() of 3264 bytes, and you
do an mq_receive() of 264 bytes, this is an error. You will not
be given the first 264 bytes of the message with the remaining 3064
bytes available to be mq_received later. mq_receive() should always
pass as it receive buffer a buffer big enough for the biggest possible
message, and if you are receiving a smaller one, it will only partially
fill your buffer. (If you have a queue size of 3264 bytes, with an
entry of 3264 bytes, and do an mq_receive() of, say, 264 bytes, I think
that QNX4’s Mqueue implementation will give you the first 2*64 bytes,
and discard the rest. I think that QNX6’s mqueue implementation will
give you an error on the mq_receive, give you no data, and not
de-queue the message. I think QNX6’s implementation is more correct
according to POSIX, and that you should not depend on QNX4’s
implementation. If you do the correct thing, which is to make sure
the mq_receive() buffer is always == the queue entry size, there will
be no problem.)
A good way to think about an mqueue is as a conveyor belt of fixed-size
buckets, say 1 litre. If you pour a 1/2 litre in, the bucket is half
full, and chugs forward 1/2 full. If you try to pour 2 litres in,
either you get an error, or the extra litre spills all over the floor,
and you have a full 1l bucket, and 1l of spilled water. At the
end of the line, when you empty a bucket, you dump the whole bucket;
if you have a one litre basin to empty it into, then you get it all.
If you have a bucket with only 1/2 litre in it, you only get 1/2
litre in the basin, cause you only empty one bucket at a time. If you
have a 1/2 litre basin and dump a 1 litre bucket into it, well, more
spilled water.
Does it needs (internally, “automagically”) "wipe"ing the remnants of a
longer previous message to put a shorter new one in?
Logically, yeah, cause it records the length (how full) each queue
entry actually is. In actual implementation, no. It doesn’t memset
data that will never be used. If you mq_send() 64 bytes to a 32*64
byte queue entry size queue that had been previously used for a full
message, it will over-write the first 64 bytes with new data, and record
that there is 64 bytes of data there. If you now mq_receive() from
that queue entry, you will be given the 64 bytes of data. The old data
is still there, but never looked at.
…if you do create the queue as 64 entries of 64 bytes, and you want to
send a message of 32*64, you will have to issue 32 mq_send() calls to
transmit this, cause each mq_send() will fill up to one queue entry.
I see both “pro” and “con” sides about this in my project… Need more
thinking…
But, is there a reason the queue can’t be longer than 64*64 bytes?
No reason actually, I’m still thinking of a way to use it properly.
You could, actually, create a queue of 64 entries of 32*64 bytes (max
message size) this would allow you to always dump a complete message as
one mq_send().
I’m thinking about it now.
If the queue is full – say it is as you say 64 entries of 64 bytes, all
filled up with low priority messages (each taking 32 entries). Then,
any send on the queue will either 1) fail with errno EWOULDBLOCK if
MQ_NONBLOCK attribute set or 2) block until a queue entry is freed.
Seems, now I get the idea.
The state of the queue changes when I read the whole message, i.e. to free
a slot if it’s bigger than the message.
So, if the queue has 64 slots of 3264 bytes - the reading of the first 64
bytes of a pending 264 bytes message WILL NOT unblock the next pending
sender, right?
Wrong. Here I have to be a bit careful, because I’m pretty sure the behaviour
changed from QNX4 to QNX6. In any case, it is an ERROR to request a receive
of less than the queue size – and you CAN NOT read a queue entry in
multiple pieces, it must be mq_receive()d in it’s entirety.
What I think will happen under QNX4: the queue entry will be removed from
the queue, and as much as will fit in your mq_receive() buffer will be
copied to your mq_receive() buffer, and then the queue entry will be
marked as available. At this point, the blocked sender will fill that queue
entry with it’s 64 byte entry and unblock.
(Under QNX6, your mq_receive() call will fail if the receive buffer size
is less than the queue size, independent of how full or empty any
particularly queue entry is.)
-David
David Gibbs
QNX Training Services
dagibbs@qnx.com