Re: ServiceLoop() Revisited

From: Per Bojsen <bojsen_at_.....>
Date: Thu Apr 21 2005 - 14:04:15 PDT
>I.e., my g() function is:
>// "g" function for Service Loop, used to cause blocking until a message is
>received
>int sLoophandler( void * context, bool pending ) {
>  return pending ? 0 : 1;
>}
>
>which I believe is the one defined in the spec for this purpose.
>
>It would have been great if this were the default mode, rather than polling,
>as it would lead to more serendipitous deterministic operation outcomes by
>users.

I'm wondering why you think so?  I've always thought that the easiest way to
achieve fully deterministic and repeatable behavior including across platforms
is to use `sane' clock control coupled with the default behavior of
ServiceLoop().  `Sane' clock control is where the user stops the cclocks
whenever he wants to transfer a message.  On input ports this means
deasserting ReadyForCclock at the same time as asserting ReceiveReady
and reasserting ReadyForCclock when ReceiveReady is deasserted upon
receiving the next input message.  On output ports the same applies but
for TransmitReady.  At Zaiq we have achieved excellent performance and
completely repeatable and deterministic tests with this approach.  I'm
stressing the performance issue here as some people might think that
applying this kind of clock control mechanism will impact performance too
much.

The problem with making the blocking use model the default is that it
is possible to deadlock the system.  Consider the following scenario:

   1) There are two input ports I1 and I2 and an output port O1.

   2) The HDL side is constructed such that a message sent to the
      input port I1 directly or indirectly eventually causes a message
      to be sent to the output port.  The processing requires cclocks
      to go by.

   3) The HDL side stops the cclocks whenever it is requesting a
      message (input ports) or wants to send one (output port).

   4) The C side has three threads: two threads T1 and T2 that does
      Send() (T1 to I1, T2 to I2) and a thread TS that executes
      ServiceLoop().

   5) Assume a message has been sent to I1 and the HDL side has not
      yet reached the point where it generates a message for the
      output port.

   6) Now assume the HDL side for whatever reason is requesting a
      message on input I2.  According to (3) the cclocks are now
      stopped and the processing required to generate the output
      message is frozen in time.

   7) Assume a cooperatively scheduled threading model such as
      SystemC's on the software side.

   8) On the software side, now assume the ServiceLoop() thread gets
      scheduled to run before T2.  ServiceLoop() is entered, no
      input messages are currently queued, so the hardware side
      does not get to restart the cclocks.  ServiceLoop() then
      enters the loop looking for pending output messages, but
      since the cclocks are stopped the next output message will
      not be created.  Hence, the g() function will cause ServiceLoop()
      to block forever.  The T2 thread will not get to run since
      threads are not preempted in the cooperatively scheduled
      threading model.

Phew!  That was more complicated to explain than I thought.  First, let
me clarify: I'm not saying your particular application suffers from this
potential deadlock.  The let me ask if you agree that the above scenario
actually does lead to a deadlock.  I think the above example does not
represent a far-fetched use scenario at all.  I.e., it is common to use
multiple threads, and have output ports that send messages in response to
input port messages.

So if the default mode of ServiceLoop() was the blocking mode, many
users might be bitten by this deadlock.

The current default behavior avoids the deadlock because it processes
all currently pending messages and then exits, allowing another pass
through the input message queue(s) again.  Of course, the user could
still deadlock their application if they did not properly allow for
thread switching.  The point is that with the blocking model it is
possible to deadlock even with thread switching 

The simplest default behavior of ServiceLoop() in my mind would be
a `fire-and-forget' mode where you call it once and it just goes
until your test is done.  Unfortunately, there is no way for the
ServiceLoop() to know that the test is finished, so the next best
thing is the current default behavior: process everything that's
pending and return to the user.  

>I thought it was in your original email: "Now, assume an implementation
>which only transfers input messages in ServiceLoop()". Did you mean "only
>transfers input messages in SL() <as opposed to immediately when Send() is
>called>  -OR- "ONLY transfers input messages in SL(), nothing else -- such
>as waiting for output messages"?

Oh, sorry, yes, I meant the former, i.e., input message are only
transferred by ServiceLoop() not Send(), or in other words, what Duaine
called buffered.

>I'm not sure we solved the ambiguity. We could write the spec that way, but
>I'm not sure we were in consensus on this?

Oh, I didn't hear you protest when Duaine was suggesting to add a note to
the spec so I assumed you were OK with that :-)

>There is an advantage in
>simplicity if input messages are non-buffered and occur in series (on the
>HDL side).

True, and I'm assuming you also want to require a strict ordering such that
Send() to port A followed by Send() to port B comes out in that order on
the hardware side as well?  I think this is where it gets sticky as each
vendor obviously wants as much freedom as possible to implement the
transport.  And as you pointed out, series reception does not really
protect you much.

>In our spare time :) ???

Yep!

-- 
Per Bojsen                                Email: <bojsen@zaiqtech.com>
Zaiq Technologies, Inc.                   WWW:   http://www.zaiqtech.com
78 Dragon Ct.                             Tel:   781 721 8229
Woburn, MA 01801                          Fax:   781 932 7488
Received on Thu Apr 21 13:58:57 2005

This archive was generated by hypermail 2.1.8 : Thu Apr 21 2005 - 13:59:21 PDT