>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 7488Received 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