Sending and receiving messages in Exapunks is a tricky business. Timing problems can ruin the proper execution of your Axiom code.

Consider these two Exas trading messages via the M register. Exa XA reads from a file and sends them to the network register M

NOTE XA - SENDER
GRAB 199
MARK READING
  COPY F M
  TEST EOF
  FJMP READING

…where XB reads from M and writes these messages to another file:

NOTE XB - RECEIVER
MAKE 
MARK WRITING
  COPY M F
  TEST MRD
  TJMP WRITING

As you can see, XA tests for the end of file (EOF), while XB tests for receivable messages (MRD). This seems to be rather well designed, but most often ends up in XB never finishing its job because there is nothing waiting in M when TEST MRD is executed. Why is that?

Transfers via the M register are not instantaneous. Before writing to M it needs to be empty, before reading from M the corresponding write operation has to be finished.

NOOP for timing

One solution for timing issues is to add additional NOOP commands in your writing loop, telling your receiver to wait until the sender is back online.

NOTE XB - RECEIVER
MAKE 
MARK WRITING
  COPY M F
  NOOP 
  NOOP 
  TEST MRD
  TJMP WRITING

If the job of XA is to just read its file and die afterwards, your programme could be written even more compact:

NOTE XA - SENDER
GRAB 199
MARK READING
  COPY F M
  JUMP READING
NOTE CRASH AND BURN AT END OF FILE

…with XB having to wait one operation less than before:

NOTE XB - RECEIVER
MAKE 
MARK WRITING
  COPY M F
  NOOP 
  TEST MRD
  TJMP WRITING

By a rule of thumb the number of instructions in your receiver loop after your last read from M and before doing TEST MRD has to be as many instructions as it takes the sender to reach its next write to M after its last write to M.

Sending „End Of Message“

If you do not want to think about timing, the receiving XB can test for a marker which tells it that the end of the message has been reached.

This only works if you know for sure that the file you are reading from never contains the symbol 0, as XA will use this as its „End Of Message“ message (EOM):

NOTE XA - SENDER
GRAB 199
MARK READING
  COPY F M
  TEST EOF
  FJMP READING
NOTE EOF, SEND EOM
COPY 0 M

The receiver XB now copies the message to T, from where it is written into the file and is also executable from TJMP or FJMP. Remember: If T is 0, it is evaluated to falseall other values will evaluate to true.

NOTE XB - RECEIVER
MAKE 
MARK WRITING
  COPY M T
  COPY T F
  NOTE TEST EOM FROM `T`
  TJMP WRITING
NOTE DELETE EOM FROM FILE
SEEK -1
VOID F

Sending „Packet Size“

If XA knows the file size it is reading to the network in advance, it is a very clever trick to send the file size to the receiver XB as well. This way the XB does not have to test for the message to end, but will know when all message chunks have been delivered.

XA will send the message size to XB and use it for its own loop:

NOTE XA - SENDER
GRAB 199
NOTE `T` CONTAINS THE NUMBER OF CHUNKS TO READ
COPY T M
MARK READING
  COPY F M
  NOTE COUNT DOWN REMAINING CHUNKS
  SUBI T 1 T
  TJMP READING

XA and XB will have the same loop conditions:

NOTE XB - RECEIVER
MAKE 
NOTE NOW `T` CONTAINS THE MESSAGE SIZE
COPY M T
MARK WRITING
  COPY M F
  NOTE COUNT DOWN REMAINING CHUNKS
  SUBI T 1 T
  TJMP WRITING

Sending „Keep Alive Messages“

For bullet-proof communication your best choice is to have XA send a „keep alive message“…

NOTE XA - SENDER
GRAB 199
MARK READING
  COPY F M
  TEST EOF
  NOTE SEND RESULT OF TEST TO M...
  COPY T M
  NOTE ...AND USE RESULT FOR YOUR OWN LOOP
  FJMP READING

…to XB:

NOTE XB - RECEIVER
MAKE 
MARK WRITING
  COPY M F
  NOTE USE TEST RESULT TO TEST FOR YOURSELF
  TEST M = 1
  FJMP WRITING

Every reading cycle XB reads two messages from M, where the second message contains 0 if XA reached the end of its file. In this manner XB continues to wait for messages as long as XA explicitly tells it to by sending 1 in the second message.

This lets you skip all timing issues on the expends of more writes to the M register. It adds just one extra line of Axiom code (but one less than having to NOOP), but may end up producing more cycles.

The Terminator

If you are facing a multi-sender communication, things may get hairy. In this scenario, multiple senders transmit data to one receiver, which has to combine these messages into a single on.

Above solutions may apply, but if you are forced to deal with different message lengths which need to be combined, if may become very tricky to shut down the other sender as well, so your receiver stops its receiving cycle.

Imagine a scenario where first sender XA knows when to quit, but second sender XB does not; in this case, receiver XC may go on receiving messages from XB ad infinitum.

To solve this problem, XA could literally use the KILL command to shut down XB. You may even opt to kill the receiver XC as well with this method.


Update 2018–09–06: Added section for „End Of Message“ & „Packet Size“.

Update 2018–09–16: Added section for „Terminator“


Andere Artikel zum Thema · · · · ·

Zuletzt geändert am

fboës - Der Blog