Host Host
.----------------------. .---------------------.
| Process | | Process |
| .-----------.| |.--------. |
| | Port|| ||Port | |
| | .--.________.--. | |
| | Port /| ||| ,--| | | |
| | .--./ `--'|| ,' |/`--' | |
| | | |----|---' /| | |
| | `--' | || /|| | |
| `----\----|-'| / |`--------' |
| \ | | / | |
| .----\--|-.|/^ | |
| | \ | |/ ^ | |
| | .--./| ^ | |
| Process| Port| ||| ^ | |
| | `--'|| ^ | |
| | || ^ | |
| | || ^ | |
| `---------'| ^ | |
`----------------------' ^ `---------------------'
^
Reliable Connection
Message order is preserved only for messages of the same priority, from the same sending port, and directed to the same receiving port. Messages with differing priority never block each other. Consequently, low priority messages may pass high priority messages, unlike in some other communication systems. Typical GM applications will either use only one GM priority, or use the high priority channel for control messages (such as client-to-client acks) or for single-hop message forwarding.
Both sends and receives in GM are regulated by implicit tokens, representing space allocated to the client in various internal GM queues, as depicted in the following figure. At initialization, the client implicitly possesses gm_num_send_tokens() send tokens, and gm_num_receive_tokens() receive tokens. The client may call certain functions only when possessing an implicit send or receive token, and in calling that function, the client implicitly relinquishes the token(1). The client program is responsible for tracking the number of tokens of each type that it possesses, and must not call any GM function requiring a token when the client does not possess the appropriate token. Calling a GM API function without the required tokens has undefined results, but GM usually reports such errors, and such errors will not cause system security to be violated.
Send Queue
+-+-+-+-+-+
.----------| | | | | |<-------------------.
| +-+-+-+-+-+ |
| gm_num_send_tokens() slots |
| |
| Receive Buffer Pool |
| +-+-+-+-+-+ |
| .--------| | | | | |<-----------------. |
| | +-+-+-+-+-+ | |
| | gm_num_receive_tokens() slots | |
| | | |
| | | | LANai Memory
- -|-|- - - - - - - - - - - - - - - - - - -|-|- - - - - - - - - - -
| | | | User Virtual Memory
| | Receive Event Queue | |
| `------->+-+-+-+-+-+ +--------+
| | | | | | |--------------->| Client |
`--------->+-+-+-+-+-+ |Software|
gm_num_receive_tokens() + +--------+
gm_num_send_tokens() slots
callback and context pointer to the send function. When the send completes, GM calls callback, passing a pointer to the GM port, the client-supplied context pointer, and status code indicating if the send completed successfully or with an error. When GM calls the client's callback function, the send token is implicitly passed back to the client. Most GM programs, which rely on GM's fault tolerance to handle transient network faults, should consider a send completing with a status other than GM_SUCCESS to be a fatal error. However, more sophisticated programs may use the GM fault tolerance API extensions to handle such non-transient errors. These extensions are described in an appendix. It is important to note that the client-supplied callback function will be called only within a client's call to gm_unknown(), the GM unknown event handler function that the client must call when it receives an unrecognized event. The gm_unknown() function is described in more detail below. Sent Packet
^
|
+-------+
|Send |
.-------------------------------------|State |
| |Machine|
| +-------+
| ^
| |
| Send Queue
| +-----------------+
| | | | | | | | | | |
| +-----------------+
| ^
| | LANai Memory
- - - - -|- - - - - - - - - - - - - - - - - - - - -|- - - - - - - - - - - -
| | User Process Memory
V |
Receive Event Queue |
+-----------------+ .---------'
| | | | | | | | | | |
+-----------------+ |
| |
| .--^--.
| gm_send_with_callback(...,ptr,len,callback,context)
| ... | |
`-> event=gm_receive(); | |
switch(event.recv.type){ | |
... | |
default: | |
gm_unknown(port,event); | |
} | `-------------|--. |
`--------. | | |
.-----|----------' | |
| | .-------|-----'
| | | |
+ - - -|- - -|- - -|- - - -|- - - - - - - - - - - +
| V V V V |
| callback(port,context,status) |
| |
| [behind the scenes in gm_unknown()] |
+ - - - - - - - - - - - - - - - - - - - - - - - - +
The following functions require send tokens:
The send token is implicitly returned to the client when the function's callback is called or, for the GM-1.0 functions gm_send() and gm_send_to_peer(), a send token is implicitly passed to the client with each pointer returned in a GM_SENT_EVENT. (The legacy GM_SENT_EVENTs are generated if and only if the legacy gm_send() and gm_send_to_peer() functions are called.)
After providing receive buffers with sizes matching the sizes of all packets that potentially could be received, the client must poll for receive events using a gm_receive(), gm_blocking_receive(), or gm_blocking_receive_no_spin() function. The gm_receive(), gm_blocking_receive(), or gm_blocking_receive_no_spin() function will return a gm_receive_event. The receipt of events of type GM_RECV_EVENT and GM_HIGH_RECV_EVENT describe received packets of low and high priority, respectively. All other events should be simply passed to gm_unknown(). Such events are used internally by GM for sundry purposes, and the client need not be concerned with the contents of unrecognized receive events unless otherwise stated in this document.
Arriving Packet
|
| ,---------------------.
V V |
+-------+ |
|Receive| Receive Buffer Pool
|State | +-------------------+
|Machine| | | | | | | | | | | |
+-------+ +-------------------+
| ^ LANai Memory
- - -|- - - - - - - - - - - - -|- - - - - - - - - - - - - - - - -
| | User Process Memory
V |
Receive Event Queue |
+-------------------+ |
| | | | | | | | | | | |
+-------------------+ `--- gm_provide_receive_buffer()
| ...
`------------------------- gm_receive()
To avoid deadlock of the port, the client software must ensure that the port is never without a receive token for any acceptable combination of size and priority for more than a bounded amount of time, that the port is informed which combinations of size and priority are not acceptable for receives, and that the client not send to any remote port that does not do likewise.
By convention, when a port runs out of low priority receive tokens for any combination of sizes, the client may defer replacing the receive tokens pending the completion of a bounded number of high priority sends, but must always replace exhausted types of high priority receive tokens without waiting for any sends to complete. Using this technique, reliable, deadlock-free, single-hop forwarding can be achieved.
The following functions require a receive token:
A single receive token is passed to the client with each of the following events:
(However, if the client passes these events to gm_unknown(), then the token is implicitly returned to GM.) Any of the GM receive functions can generate these types of events. These functions are:
1.4.4