Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementation of MSG_TYPE_PORT_ABSENT in reactor-ts #105

Closed
hokeun opened this issue Jul 5, 2022 · 10 comments · Fixed by #198
Closed

Implementation of MSG_TYPE_PORT_ABSENT in reactor-ts #105

hokeun opened this issue Jul 5, 2022 · 10 comments · Fixed by #198
Assignees

Comments

@hokeun
Copy link
Member

hokeun commented Jul 5, 2022

MSG_TYPE_PORT_ABSENT is a message sent by an output control reaction when the output is going to be absent.

See here for more details.

@hokeun
Copy link
Member Author

hokeun commented Jul 20, 2022

This might be an interesting next project for @ByeongGil-Jun

@hokeun
Copy link
Member Author

hokeun commented Jul 25, 2022

This is a comment where port absent message was mentioned: lf-lang/lingua-franca#538 (comment)

@hokeun
Copy link
Member Author

hokeun commented Jul 25, 2022

FYI @ByeongGil-Jun on federated execution AST transformation: lf-lang/lingua-franca#1212

@hokeun
Copy link
Member Author

hokeun commented Jul 25, 2022

FYI @ByeongGil-Jun on network control reactions: lf-lang/lingua-franca#608

@hokeun
Copy link
Member Author

hokeun commented Aug 2, 2022

@lhstrh This is the tracking issue for port absent messages. Thanks!

@byeonggiljun
Copy link
Collaborator

Below is the logic to execute reactions considering network control reactions and port absent messages in TypeScript federated execution. The logic introduces two separate queues for reactions waitingReactionQ and readyReactionQ, (previously just one reactionQ).

LastKnownStatusTag: Tag indicating the last time when the port received port absent message or tagged message.
waitingReactionQ: Queue of reactions that are not ready to run. We should pop the reaction from this queue and push it into the readyReactionQ.
readyReactionQ: Queue of the reactions ready to run. If the reaction is the network input control reaction and the return value is waiting, we should insert this reaction again in waitingReactionQ as well as the reactions to run after the reaction that must wait.
First, insert all reactions that have a network input port into waitingReactionQ, (no network control reaction added yet at this point).

This is a while loop. This loop exits only when waitingReactioinQ and reactionReactionQ are empty.
Check all reactions in the waitingReactionQ in order and move them to the readyReactionQ. If any port has unknown status, the reaction can’t be inserted into the readyReactionQ. In this case, we should insert a networkInputControlReaction into the readyReactionQ.
Do react for all reactions in readyReactionQ. In inputControlReaction, we check the lastStatusKnownTag for input ports. Unknown port means the current tag is larger than the lastStatusKnownTag. If the lastStatusKnownTag is updated by RTIclient, after receiving a port absent message or a tagged advance message, or a tagged message, inputControlReaction updates the status of the port. The corresponding reaction can be inserted into the readyReactionQ, if the port received a tagged message, or just popped from waitingReactionQ if the port received a port absent message.
Go to 1.

After that, we should trigger all networkOutputControlReaction s into the readyReactionQ. The networkOutputControlReaction sends the port absent message if the output port is absent at this tag.

@lhstrh Could you please give us suggestions on where we should add the last known status tag? There are two suggestions by @hokeun. One is inside the port, and the other one is a map outside of the port.

@byeonggiljun
Copy link
Collaborator

byeonggiljun commented Aug 25, 2022

@lhstrh Below is what I found about waiting networkInputControlReaction by using async/await. It would be a great pleasure if you read it and tell me your thoughts.

There are two problems.
First, how can we suspend and control back in the right way?
Second, how can we scan and process the RTI messages while the _react is suspended?

For the first question, we should make all caller functions of _react() be an async function and put await carefully.
These are four scenarios that _react() is called.

  1. _startExecuting_react()
  2. _startExecuting_next()_react()
  3. TagAdvanceGrant or ProvisionalTagAdvanceGrant_requestImmediateInvocationOfNext()setImmediate()_next()_react()
  4. setAlarmOrYieldalarm.set()_next_react()

It would be possible to apply async/await if these complex connections are just obstacles. However, we have to consider RTIClient, too. Because the main loop of federated execution is this loop. For example, at the start tag, this emit code is executed and this on function is invoked. After all codes in that function are executed, RTI can invoke other emit codes to make FederatedApp process them. So we should change the function of RTIClient, too.

And the second problem raises here, dealing with RTIClient. The FederateApp can't process another message from RTI before it finishes emitting code in handleSocketData. For now, this function is called only at this code. If we turn _react to an async function and put await, it should get a promise return value from that handleSocketData function. The problem is, when we call handleSocketData from _react, it might execute _next again, and we should prevent that happen. Whole functions, emitting message processing codes, _next() and _react(), _requestImmediateInvocationOfNext() are intricately connected.
I think that we should change the whole logic of the federation.ts and reactor.ts to use the async/await.

What is the better way to address this waiting problem, keep my previous solution, or start the discussion to apply async/await? Thank you!

@edwardalee
Copy link
Collaborator

I don't know enough about concurrency in TypeScript to offer advice here, but maybe it's worth understanding the big picture. The networkInputControlReaction should behave just like a long-running reaction. It suspends because there is insufficient information to invoke reactions that depend on it.

In TS, if you have a long running reaction (even an ordinary reaction), what happens to messages from the RTI during that reaction's execution? Why wouldn't the same mechanism work for networkInputControlReaction?

@byeonggiljun
Copy link
Collaborator

@edwardalee It's not straightforward to implement the same long-running reaction with suspending and resuming in reactor-ts because reactor-ts runtime is currently single-threaded.

So for now, networkInputControlReaction is implemented as an alternative way(relevant PR: #117), although the logic isn't the same as reactor-c. That is, netwokrInputControlReaction just returns rather than waiting to execute the message processing routine. And then come back to the networkInputControlReaction with previous states.

@edwardalee
Copy link
Collaborator

I see. It looks like the implementation repeatedly invokes the networkInputControlReaction until the _react function returns false. I.e., it does a busy wait. I guess this should work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants