I noticed you have already incorporated my proposed language for IM33 in rev 1.0.7. However, at last meeting we decided to ban the reuse of SceMiMessageData objects passed to the Receive() callbacks, so I've updated my proposal for the Receive() callback as follows: In Section 5.4.7.1, document p. 55, PDF p. 63, replace the last paragraph in the section with: It shall be an error if the class SceMiMessageData object passed to the receive callback is passed as the class SceMiMessageData argument of the SceMiMessageInPortProxy::Send() method. Modifying the class SceMiMessageData object by casting away const leads to undefined behavior. The language for Send() that you've already added remains the same. =============================================== > I carefully reviewed this thread and thought about it a bit. > One thing I think we still want to do is keep SceMiMessageData > construction and re-use to be something managed by the user. And this implies you believe reuse of input messages at least should be allowed, right? > On the one hand, I think this would be useful to receive an output > message and within the same receive callback function tweek a couple > of fields and turn it right around and send back to H/W on an input > port. While this could be useful, the definition of the receive callback strongly suggests modifying the message is not supported due to the const message argument. Of course, there will be implementations that would allow casting away const'ness and modifying the message, but that would be non-portable. So it seems we are forced to accept that the standard does not condone modifying output messages and given that, reuse of output messages have limited value. After all, one can always copy the contents of the message to another one. In fact, we could define a SceMiMessageData copy constructor to make it convenient for the user. So it seems to make sense to ban reuse of output messages which gives implementations that extra degree of freedom in choosing message internals. =========================================== I carefully reviewed this thread and thought about it a bit. One thing I think we still want to do is keep SceMiMessageData construction and re-use to be something managed by the user. A typical example might be a queue and free-pool of reusable data packets all sized for use with a specific port. There may be times in the simulation when a number of such packets exist in the queue and so having one message data tied to the port would be restrictive and would require data copying from queued packets on each send. So I think we want to keep this capability is it is. However, as to re-sending output messages to input, I can see pros and cons to making a restriction here. On the one hand, I think this would be useful to receive an output message and within the same receive callback function tweek a couple of fields and turn it right around and send back to H/W on an input port. This would avoid data coping to a second message data object that is to be used on input. Also would not even require allocation of a second message data on the fly or stored in some global area or in the context pointer area. So long as the input port and output port widths are the same, the packet would be reusable. On the other hand, I can understand Per's concern that message data's used for input might have different "internals" than message data's used for output. As for cyclestamps here is my suggestion: 1. We keep CycleStamp() in messages themselves. Having messages that carry along timestamps of when they were sent is quite useful. 2. If a SceMiMessageData is constructed and the CycleStamp is queried it would return 0. 3. Aside from CycleStamps in messages, it would be useful to have a global CycleStamp accessor - possibly a method of class SceMi that returns the CycleStamp of the last message received. This would allow applications to query the current time of the H/W side at any time without having to track the cyclestamps returned with each message. We're seeing in several applications where this would be useful. ====================================================== It's a valid point that the SceMiMessageData class could represent an interface to the actual transfer data rather than an object for storage. The implementations I've used (all one of them) don't do it that way and the language that's in the spec regarding the objects having the same width as the ports they're sent to hints that the objects are separate and self-contained rather than interfaces. Nevertheless, after these last couple emails, it's hard to argue that a clarification is not in order! Maybe you could work the word "persistent" into your proposed language? Not that this is doable at this late date but I guess it would make more sense to me if the SceMiMessageData class were folded into the two Proxy classes -- that would eliminate the CycleStamp issue and generally simplify things. Each proxy would encapsulate its own MessageData and the user wouldn't have to fool with a separate construction of a MessageData object, and be sure it's the same width as the proxy. If SCEMI ever implements variable message lengths, this would be more suitable for that, I believe, since you wouldn't have problems with port and message data width discrepancies occuring dynamically. To address multiple data copy issues, it would be cool to be able to set up an input port proxy to hold references/pointers to data space elsewhere, or to have it call a user function that could be used to do some assembly of message data every time Send() is called. Just musing out loud. ===================================================== > I believe the spec adequately describes the limited scope and lifetime > of SceMiMessageData objects received through an OutputPortProxy. Agreed, but the issue was not this, but whether the spec allows or should allow these objects to be sent to input ports. Although this is a minor issue and probably uncommon usage, what the spec says does affect the implementation. For instance, if the spec explicitly forbids this usage, then the implementation could take advantage of this in how it internally handles and implements SceMiMessageData objects. Note, the SceMiMessageData class is only the interface the application sees and more state may be kept under the hood that differs depending on the direction of message transport. > I would suggest, without any real fervor, that whether a user chooses > to construct once and store SceMiMessageData objects for use with an > InputPortProxy or "use once and discard" is an implementation detail > best left to the users and requires no further clarification. The point of adding the clarification was to ensure that all SCE-MI implementations support both of these use models. This is important for portability. If we do not specify whether reusing SceMiMessageData objects are allowed or not, then there is a risk that eventually some implementations will allow it while others will not. > Since we're dealing with a C++ class here, and we're passing it to > Send() via a const reference, the proposed clarification amounts to a > C++ truism. It is not that simple because the SceMiMessageData class is just the interface. There is no requirement in the spec that the SceMiMessageData class contain all the information related to a message. It is quite possible to envision a case where forbidding reuse of SceMiMessageData objects could lead to a more optimized implementation. In fact, allowing reuse makes it harder for the implementation to avoid a data copy. > The requirement that SceMiMessageData objects have the same width as > the ports they're sent to is addressed in the description of the > constructor in 5.4.5.1 True. Removing this, the proposal is now: Send() In Section 5.4.6.1, document p. 53, PDF p. 61, after the sentence under `data' add: This object may be arbitrarily modified after Send() and used for an arbitrary number of sends to the same and other message ports. Receive() In Section 5.4.7.1, document p. 55, PDF p. 63, after the last paragraph in the section add: The class SceMiMessageData object passed to the receive callback may be sent any number of times to any number of input ports. Modifying the class SceMiMessageData object by casting away const leads to undefined behavior. > Changing subjects, after reading the spec some more, I found what > might be a separate issue. The CycleStamp() accessor for > SceMiMessageData objects is presented in the spec (p52, PDF 60) > without any description of what would happen if a renegade user were > to call it on a SceMiMessageData object not originating from an > OutputPortProxy. Should the accessor call the port's error handler in > this case, return 0, or is "undefined behavior" adequate? I don't think undefined behavior is good. I think it makes sense to make this an error, but unfortunately, CycleStamp() does not have a SceMiEC argument so we cannot make it an error without changing CycleStamp()'s declaration. If doing this is not an option, the only reasonable choices left are to return 0, or, perhaps better, return the most recent value of cycle stamp received through an output proxy. ======================================================= It surprised me that reuse of SceMiMessageData objects would be considered an issue, since we've always constructed and reused them for sending through InputPortProxys and I believe the spec adequately describes the limited scope and lifetime of SceMiMessageData objects received through an OutputPortProxy. I would suggest, without any real fervor, that whether a user chooses to construct once and store SceMiMessageData objects for use with an InputPortProxy or "use once and discard" is an implementation detail best left to the users and requires no further clarification. Since we're dealing with a C++ class here, and we're passing it to Send() via a const reference, the proposed clarification amounts to a C++ truism. That said, the only harm the proposed language could do would be to add a little clutter to the spec. The requirement that SceMiMessageData objects have the same width as the ports they're sent to is addressed in the description of the constructor in 5.4.5.1 Changing subjects, after reading the spec some more, I found what might be a separate issue. The CycleStamp() accessor for SceMiMessageData objects is presented in the spec (p52, PDF 60) without any description of what would happen if a renegade user were to call it on a SceMiMessageData object not originating from an OutputPortProxy. Should the accessor call the port's error handler in this case, return 0, or is "undefined behavior" adequate? ======================================================== I took the action to check if the spec needs some language to clarify that reusing SceMiMessageData objects and resending them is OK. The current spec neither forbids nor explicitly allows this usage. This means it is likely that different implementations will do different things and it would seem useful to add clarifying language. Send() In Section 5.4.6.1, document p. 53, PDF p. 61, after the sentence under `data' add: This object may be arbitrarily modified after Send() and used in an arbitrary number of Send() invocations to the same as well as other message ports as long as these all have the same width. Receive() In Section 5.4.7.1, document p. 55, PDF p. 63, after the last paragraph in the section add: The class SceMiMessageData object passed to the receive callback may be sent any number of times to any number of input ports as long as the width of each of these ports is the same as the width of the output port causing the receive callback. Modifying the class SceMiMessageData object by casting away const leads to undefined behavior. =================================================== I don't think the standard currently prohibits this, but is it legal to modify a SceMiMessageData object received in a Receive() callback and/or Send()'ing it to some input port? I assume yes, since the standard did not explicitly prohibit this. While this seems on the oddball side, I can see that it might be useful in certain debug scenarios. Nevertheless, if it is not strictly prohibited some user will do it and I have to make sure my implementation handles it correctly :-) Per