# Interprocess Communication: adap

Interprocess Communication

Client-Server Communication
Callback Functions and Events
Table: adap Asynchronous Interprocess Communication Event Types

The adap Data Structures

Service Descriptors for Interprocess Connections
Table: Service Descriptor Attributes
Protocols for Sending and Receiving Data
Service Handles

Timeouts in Synchronous Communication
Communication Errors

Table: Errors in Synchronous Communication

Definitions of adap Functions and External Functions
(for a listing, with links, of these functions alphabetized by their A+ names, click here)

Asynchronous Send adap.Send{h;x}
Close Handle adap.Close{h}
Connect adap.Connect{s;f}
Debug Flag adap.Debug{f}
Export Data adap.Export{x}
Get Attribute Value adap.Of{h;s}
Get Client Data adap.GetClientData{h}
Get Port and Workstation Information adap.GetPort{h}
Get Timeout adap.GetTimeout{t}
Import Data adap.Import{x}
Listen adap.Listen{s;f}
Modify Timer adap.ModifyTimer{h;s;d}
Reset adap.Reset{h}
Set Attribute Value adap.Has{h;x}
Set Client Data adap.SetClientData{h;x}
Set Timer adap.SetTimer{h;f;d}
Status of the Read Queue adap.ReadQueueStatus{h}
Status of the Write Queue adap.WriteQueueStatus{h}
Synchronous Exchange adap.SyncXch{h;x;t}
Synchronous Read adap.Syncread{h;t}
Synchronous Send adap.Syncsend{h;x;t}

> The adap context is native to A+; there is no need to load adap. "idap.+" is loaded automatically when the interpreter is started. idap.+ installs backward-compatible behavior on top of the automatically loaded i context, which uses the MSIPC class of MStk.

> DAP (Distributed Analytics Platform), a set of tools supporting interprocess communication, has been used extensively in non-A+ applications. The functions in the adap context are a layer on top of DAP, providing application writers with the means to:

> - establish and maintain communication between pairs of processes, such as a client-server pair;

> - specify the format of the data to be interchanged by a communicating pair of processes; and independently, to

> - establish and maintain timer events.
> Both asynchronous and synchronous interactions are supported. In asynchronous interactions using the A protocol (cf. "Protocols for Sending and Receiving Data", and especially "The A Protocol"), both single and burst modes are supported. These tools are in the adap context, which is always available in an A+ session.

# Interprocess Communication

> Communication based on adap is carried out between two processes - A+ processes or not - , but not directly among more than two. The mode of communication can be either synchronous or asynchronous. In synchronous communication, one partner sends a block of information to the other and is blocked from further action until it receives a response. In asynchronous communication, one partner sends information to the other and then simply goes about other business; if there is a response to what was sent, it is processed whenever it arrives. Thus one partner might send several independent requests, each requiring a response, before the response to any one of them is received. When one process is communicating asynchronously with several others and receives messages from more than one of the them, there is no guarantee that they are received in the same order they were sent. Only this is certain regarding the order of events in asynchronous communication: if a process sends more than one message to one particular partner, the messages will be received in the order in which they are sent.

> At first thought, synchronous communication may appear to be somewhat easier to manage than asynchronous, but in general it is not, and it is of less general use. Synchronous communication can be used most effectively when one partner has nothing else to do but wait for the response from the other. Likewise, asynchronous communication may appear to be more complicated because messages are processed whenever they arrive, and there is no way to know when the arrivals will occur, or - when there is more than one source of messages - in what order. However, adap's way of managing asynchronous communication, namely events and callback functions, is quite straightforward.

> The rules for interprocess communication are strictly up to the partners. It can be agreed that one partner always processes requests from the other; that either partner can initiate a request of the other; that either partner can send a message at any time; that not all requests require a response; and so on.

> Establishing a communication channel is not a symmetric procedure; one partner is designated to listen for the other, while the other attempts to connect to the listener. The listener initiates its end of the communication channel by executing adap.Listen. The other partner executes adap.Connect. For convenience they will be called the listening partner and connecting partner, respectively. In principle, it doesn't matter which partner happens to go first1. If the listening partner goes first, the effect of executing adap.Listen is to continually listen for connecting partners; if the connecting partner goes first, the effect of executing adap.Connect is to continually attempt a connection until the listening partner starts listening. Once both partners have attempted to establish communication, the communication channel is formed.

> Even though the listening partner continues to listen and the connecting partner continually attempts to connect to its partner until successful, both adap.Listen and adap.Connect return immediately after being executed, for otherwise the partners would not be free to do other work. The status of the underlying listen and connection attempt are monitored with callback functions on adap events.

> The asymmetry in establishing communication is also reflected in the fact that the connecting process can link up with only one partner for each execution of adap.Connect, while the listening process can link up with many partners with just one execution of adap.Listen. Executing adap.Listen causes a listening port to be established, which remains open to receive connecting partners until the listening partner shuts it down. Executing adap.Connect causes a connecting port to be established, over which the connecting partner continually tries to connect to one and only partner, until either it is successful or the connecting partner shuts it down.

## Client-Server Communication

> Client-server communication is an important, commonly used mode of communication. It is the mode by which one partner, the client, typically takes the lead in communication with a server, by specifying the services to be performed; the server is the passive partner, waiting for requests from clients before taking action.

> The server may provide a common service for many clients, such as real time data access, or a dedicated service, such as data base access and analytic computations. In the former case the server is the listening partner because of the one to many nature of its service; it is probably started automatically by some means of the operating system, and is always available. In the latter case, the client-server model may be used simply for load balancing; the server may actually be started by the client, and may be the connecting partner.

## Callback Functions and Events

> An event is an asynchronous change in the state of an application which can trigger an action by the application. There are two classes of events that are of concern in adap applications, interprocess communication events and timer events. Interprocess communication events mark significant changes in the communication state between processes, while timer events mark time interval expirations. The means by which an application program takes action is a callback function, which is automatically called when the event takes place.

> For example, when a client requests a connection to a server, a callback function in the server application is automatically invoked so that the server can register the client. When a message from the client to the server is ready to be received, a callback function is automatically called so that the request can be processed. Similarly, when the message sent back to the client is ready to be received, a callback function in the client application is automatically called. In this manner a server can process random, or asynchronous, requests from clients, and a client can continue with other tasks, but still process responses from servers as they arrive.

> Interprocess communication events fall into several categories, called event types. For example, the receipt of a message from a partner is an event of type `read. The callback function for the receiving partner's service handle (which identifies the connection) is called with arguments identifying the event type and the partner that the message is from. There is a small, fixed set of event types in adap (see the table "adap Asynchronous Interprocess Communication Event Types"); typically a callback function consists of a single case statement with a case for each type.

> Callback functions are established for the partners when they call adap.Connect and adap.Listen. All adap callback functions have three arguments, and their meanings are always the same:

>       CallBackFunction{service_handle;event_type;call_data}

> In interprocess communication, service_handle, which is a scalar integer, is the means by which communicating partners identify one another (see "Service Handles"); event_type indicates the general class of the action that caused the callback to occur (see table below); and call_data holds data associated with the action (see table below). In the case of event type `read, the associated message is call_data.

> adap Asynchronous Interprocess Communication Event Types
> (Callback Function CBF{service_handle;event_type;call_data})
> Event Type | Description And Action To Be Taken
> --- | ---
> `choose | A choose event occurs when only `name is specified in a service descriptor argument to adap, and more than one service has a matching service name. In this case call_data is a vector containing a complete service descriptor for each matching service. The result of the callback function should be one of these service descriptors. Note: it is not always useful for a callback function to produce a result, but in this case it is.
> `connected | A connected event indicates to both the listening and connecting partners that a connection has been made. For example, a server would typically add the client identified by service_handle to a list of clients and perhaps perform some initialization, while a client would start off the client-server communication by sending a message to the server.
> `error | An error event indicates that something has gone wrong from which adap cannot recover. Unlike the reset event (see below), it is left to the application to recover from an error event: to call adap.Close on the handle and then either to restart if possible or to terminate gracefully. No attempt is made to qualify the type of error that occurred.
> `read | A read event indicates that a complete message has arrived from the partner identified by service_handle, i.e., the entire message sent by the partner with one call to adap.Send has arrived. The data, i.e., the contents of the message, are in call_data. In burst mode (in the A protocol), all pending complete messages from the same service handle are included in call_data, each as an enclosed element; see rEventMode.
> `reset | A reset event indicates to either partner that the connection between the pair has been broken, either by the partner closing his end of the connection, or by a recoverable system error. For example, a server would typically remove the client indicated by service_handle from the list of clients it is processing and close that service handle. A client would either explicitly close its service handle or, by doing nothing, allow the system to try to reconnect by automatically recalling adap.Connect. (The listening partner cannot maintain the old connection handle and wait for the connecting partner to reconnect, because the new service handle of the connecting partner will be different.)
> `sent | A sent event indicates that one or more pending messages have been sent to the partner identified by service_handle. Messages are not necessarily sent immediately by adap.Send; some may remain pending and will be sent by adap at a later time. Messages that are sent immediately do not cause sent events. Rather, sent events occur when pending messages are actually sent. call_data is the number of pending messages sent. The total of the call_data values for all sent events plus the total of all results of adap.Send equals the number of messages sent to the partner.

> Timers work a bit differently. Expiration is really the only event type for a timer. Consequently, if callback arguments for timers were the same as callback arguments for interprocess communication, the second argument for calls to timer callback functions would always have the same value, and so be useless. Therefore, timer event types have been defined to be the names of timers; a name is given when a timer is established (see adap.SetTimer). This means that timer event types are not a fixed set as in interprocess communication, but are determined by the application writers. In practice, of course, they are a fixed set within each application.

> That the only true timer event type is expiration means that the callback function of a timer is called only when the timer expires.

> The service_handle argument of a timer callback function is of use when the timer is to be closed or modified before it expires. The call_data argument is the time duration with which the timer was established (see adap.SetTimer), thus permitting the callback function to reset the timer with a related duration.

> Each timer is established by calling adap.SetTimer, and its callback function is identified in that call. Consequently, each timer could have a separate callback function, but it is common practice to use one callback function consisting of a single case statement, where the cases are the names of the timers (see adap.SetTimer).

# The adap Data Structures

## Service Descriptors for Interprocess Connections

> A service descriptor is a nested vector describing the connection a connecting partner is attempting to establish with the listening partner, and the connections the listener is willing to accept. The partners agree beforehand on the contents of this vector. The elements of the vector are arranged in attribute-value pairs; i.e., the vector is an association list. The first element of an attribute-value pair is the service attribute, and is one of `host, `port, `protocol, or `name. The second element of a pair is an appropriate value for the service attribute. These attributes can be set on a listener, and their values will then be given to any connection it establishes. (The `retry attribute is explicitly turned off and `listener is reference only.) See the "Service Descriptor Attributes" table.

> For example, the following service descriptor uses the sample values in that table:
> (`host;`s5; `port;9004; `protocol;`A; `name;`ThisService)

> The order in which the attribute-value pairs appear is immaterial, although each attribute symbol must be followed immediately by its value. For example, the above service description is equivalent to:
> (`name;`ThisService; `host;`bilbo; `protocol;`A; `port;9004)

> If the name of the listening partner is registered in the operating system, it is only necessary to specify the name in the service descriptor; e.g. (`name;`idn_apc).

> Service Descriptor Attributes
> Service Attribute | Description | Sample Value, Default
> --- | --- | ---
> `host | The name, as a symbol scalar, of the host machine on which the listening partner runs. If both partners run on the same machine, then `localhost can be used. For adap.Listen, `host must be the local host; it can be given as its name, `localhost, or null. | `bilbo (not necessarily a real host name). Default when anything other than `name is specified: `localhost.
> `listener | Reference only. This attribute is valid for connections. For those created by listeners, the value is the handle of the listener which created the connection. For "client" connections created through direct calls to i.connect* functions, the value of the `listener attribute is 0. |
> `name | The name, as a symbol scalar, of the service. Some services are listed in the system yellow pages, and for them only their names need be given in service descriptors (see the `choose event type in the table "adap Asynchronous Interprocess Communication Event Types"). For others a complete service descriptor must be given, and the name serves only as an abstract identifier of the connection. | `ThisService
> `port | The port on which the communication takes place. Port numbers are controlled by the system administrators. 0 means that adap should pick any available port; the number of the port chosen by adap will be the first element of adap.getPort{servicehandle}, and it is the application's responsibility to notify potential partners of it. | 9004. Default when anything other than `name is specified: 0.
> `protocol | The name of the format, as a symbol scalar, in which data is sent and received by the partners. See "Protocols for Sending and Receiving Data". | `A, for sending and receiving A+ arrays. Default when anything other than `name is specified: `A.
> `retry | If 1, adap attempts to re-establish the Listen connection if the first try fails. If 0, it does not, perhaps the more reasonable course. | 0

## Protocols for Sending and Receiving Data

> A+ applications can use adap to communicate with other A+ applications and with non-A+ processes, in particular real-time data sources. There are different formats of the A+ data, or protocols, for the different types of partners: the A and simple protocols are used when both partners are A+ applications. In addition, there are the raw and string (as well as simple) protocols for sending or receiving unformatted character strings, and the ipc protocol for communicating with certain non-A+ processes that expect that protocol. The ipc protocol is not documented here.

> The first contact with arriving real-time data is made by the line-reader processes, which format the input streams into discrete messages.

> The raw protocol can be used to communicate with the lowest level of these processes, the line readers. Most A+ applications deal with the higher level protocols, but, as you can see, it is possible to establish communication at any level of the real-time data management scheme.

The A Protocol

> The A protocol is for sending and receiving A+ arrays between A+ applications; it is specified in the protocol portion of the service descriptor as `A. These arrays cannot contain function expressions. The array is actually transmitted in CDR format (see Import an A+ Array, sys.import).

The simple Protocol

> simple is designed as a fast, simple A+ protocol; it is specified in the protocol portion of the service descriptor as `simple. It is similar to the A protocol but does not accept nested, symbolic, or functional data. That is, it takes only simple integer, float, or character arrays, ones that can be mapped. The simple protocol does not use import or export (no CDR format), so an A+ object sent can be easily reconstituted in a C process. It does include a four-byte header containing the length of the A object in bytes.

The raw Protocol

> The raw protocol is to communicate with non-A+ processes that send and receive character strings; it is specified in the protocol portion of the service descriptor as `raw or `RAW.

The string Protocol

> string has more general appeal for communication between A+ and C processes than simple does. It is similar to raw, except that it includes a four-byte header with the length of the message, and ensures that only complete messages are delivered. (This differs from raw, in which a single send may come out as several reads, or vice versa.) It accepts (and delivers) only character vectors. It is specified in the protocol portion of the service descriptor as `string.

## Service Handles

> Whenever a listening partner initializes a service by executing adap.Listen, it receives as a result of that function an identifying integer known as a service handle. From the point of view of the application, this integer is simply an abstract identifier. In the case of adap.Listen, the service handle identifies the listening partner to itself.

> When the listening partner accepts a request to connect from a connecting partner, a service handle identifying that partner is generated. Similarly, when a connecting partner requests a connection with a listening partner, a service handle identifying the listener is generated. These service handles should be saved because they are means by which partners are identified.

> There are four types of service handles, including the three just mentioned:

> - a listen handle identifies the listening partner to itself, typically for the purpose of closing the communication channel at some later time, and is the result of adap.Listen;

> - an accept handle identifies a connecting partner to the listening partner, and is the first argument to the listening partner's callback function when a connected event occurs;

> - a connection handle identifies the listening partner to a connecting partner, and is the first argument to the connecting partner's callback function when a connected event occurs;

> - a timer handle identifies a timer, and is the result of adap.SetTimer.
> Every service handle, including those for timers, should be saved for the purpose of closing the connection later.

# Timeouts in Synchronous Communication

> When a process sends a message to its partner synchronously, if no provision had been provided to interrupt the sending function, it will not return until the message is sent. If time is crucial, the wait may be unacceptable; it might be better to interrupt the sending function and try again later. The function that adap provides for sending messages synchronously, adap.Syncsend, has a timeout argument. If the timeout expires before the message is completely sent, the underlying message-sending mechanism is interrupted and adap.Syncsend returns. There is a timeout argument to the function for synchronously reading messages as well.

> If a timeout occurs then all that is known about the message is that it has been partially sent or partially received, but the exact state is unknown. The only way to clear the pending message fragments is to force a reset.

> A timeout argument indicates the duration of time during which attempts will be made to complete a synchronous operation. The form of a timeout is either a numeric scalar or one-element vector, or a two-element integer vector. In the case of a numeric scalar or one-element vector, the value represents seconds, and any fractional part of the number represents fractions of seconds. In the case of a two-element integer vector, the first element represents seconds and the second element represents microseconds. For example, 2, 2.5, and 2 500000 are all valid timeouts.

> An alternative timeout form is to specify the clock time by which a synchronous operation must be completed, or else abandoned. This form is a three-element integer array, where the first element represents seconds since the Epoch (see sys.secs_in_Epoch), the second element represents microseconds, and the third element is 1.

> The two forms of timeouts are called duration timeouts and clock timeouts.

# Communication Errors

> In asynchronous operations, an unrecoverable system error results in a callback with event type `error, while a recoverable system error results in a callback with event type `reset. For synchronous operations, however, no analogous default actions are taken. This means that the application writer is responsible for examining the error and determining if a `reset needs to be sent to the partner (see adap.Reset).

> The errors that the synchronous functions can report (as indicated by the second element of an error return) are listed in the next table.

> Errors in Synchronous Communication
> Error Name | Description And Action To Be Taken
> --- | ---
> `buffread | Call adap.Reset.
> `buffwrite | Call adap.Reset.
> `fdsisset | Call adap.Reset.
> `nochan | Call adap.Reset.
> `select | Call adap.Reset.
> `readImport | This error indicates that adap.Syncread received a bad A+ object. It may or may not require a reset. More likely, it indicates a bug in the partner. (A bad A+ object is one that does not conform to the A protocol, which must be used in synchronous communication; see "Protocols for Sending and Receiving Data".)
> `export | This error indicates that the argument to adap.Syncsend is an invalid A+ object (perhaps one with function pointers). Reset is not necessary.
> `interrupt | This indicates that a system interrupt occurred while the operation was in progress. A reset need not be called, but you should continue execution so that the interrupt can be processed. (Note that processing the interrupt may well cause a reset or even termination of the program.)
> `timeout | This indicates that the function did not finish before the timeout was reached. Whether or not a reset is necessary is up to the application.

# Definitions of adap Functions and External Functions

## Asynchronous Send adap.Send{h;x}

Arguments and Result

> h is a service handle, as described in "Service Handles". x is any array. The result is a scalar integer.

Definition

> This function is used by either communicating partner to send a message to the other one. The message is the array x. If possible, the message is sent immediately. If not, the message is considered pending, and will be sent at some later time. adap.Send sends only one packet (2K, perhaps) synchronously (i.e., before it returns); the rest is transmitted during later calls to this function or when the process returns to the mainloop. If the message is sent immediately, any pending messages will also have been sent. The contents of the message x depend on the protocol being used (see "Protocols for Sending and Receiving Data").

> The result is the number of messages sent. The number is 0 if the current message x is not immediately sent, and it may be greater than 1 if this message and pending ones are immediately sent. Any messages immediately sent by this function will not cause a `sent event; see "Protocols for Sending and Receiving Data". Note that a result of 0 can also arise if the function fails, which can happen, for example, if the arguments are invalid.

> A cumulative total of the results of this function and the call_data arguments to `sent callbacks equals the total number of messages sent to the partner.

## Close Handle adap.Close{h}

Argument and Result

> h is a service handle, as described in "Service Handles". The result is a scalar integer.

Definition

> This function closes the service handle h. All system resources associated with this service handle are deleted. In the case the service handle h was established through adap.Listen, previously established connections for the listening partner are maintained, but no new ones will be established. If the listening partner wishes to terminate service completely, in addition to closing its service handle h, it must explicitly close all accept handles it has previously received for h; the listening partner is responsible for maintaining a list of accept handles.

> Service handles for timers can be closed with adap.Close before their set times expire; they are automatically closed when their set times expire, and therefore, the timers can be said to expire.

> The result of this function is 1 if the connection is successfully closed, i.e. if the service associated with it is found and closed, and 0 otherwise.

> The requirement to explicitly close connections when they are no longer needed is the main reason for saving the service handles produced by adap.Connect, adap.Listen, and adap.SetTimer.

## Connect adap.Connect{s;f}

Arguments and Result

> s is a service descriptor, as described in "Service Descriptors for Interprocess Connections". f is a callback function, as described in "Callback Functions and Events". The result is a service handle, as described in "Service Handles".

Definition

> This function is used by a connecting partner to establish communication with a listening partner. See "Interprocess Communication". The result is -1 if the function fails, which can happen, for example, if either argument is invalid.

## Debug Flag adap.Debug{f}

Argument

> The argument is a scalar integer.

Definition

> Immediately after execution of adap.Debug{1}, adap displays trace messages in the A+ session as it is executed. Immediately after execution of adap.Debug{0}, most adap messages are suppressed; some error and warning messages are still issued. A "zero-length message" warning indicates a real problem with a socket, and, even though the message may be suppressed, the condition may cause the process to burn CPU cycles.

> When a problem occurs with adap, you can help the adap developers resolve it if you can repeat the error after executing adap.Debug{1} and send them the resulting A+ session log.

## Export Data adap.Export{x}

> This function has been superseded by sys.exp.

## Get Attribute Value adap.Of{h;s}

Arguments and Result

> The left argument h is a service handle, as described in "Service Handles". The right argument s is a symbol. The result is an array.

Definition

> The result is the value of the attribute named in the right argument s for the service handle h. See adap.Has.

## Get Client Data adap.GetClientData{h}

Argument and Result

> The argument is a service handle, as described in "Service Handles". The result is an array.

Definition

> The result of this function is the client data previously associated with h by adap.SetClientData. If no client data has previously been set or if h is not a currently active service handle, the value is Null.

## Get Port and Workstation Information adap.GetPort{h}

Argument and Result

> The argument is a service handle, as described in "Service Handles". The result is a five-element integer vector.

Definition

> The first element of the result is the port number for the service handle, and the last four elements are the conventional Unix network id for the current host machine.

## Get Timeout adap.GetTimeout{t}

Arguments and Results

> The argument t is a duration timeout, as described in "Timeouts in Synchronous Communication". The result is a clock timeout.

Definition

> The argument t represents a number of seconds, possibly fractional. The result is the clock time t seconds after the function is called. For example, adap.GetTimeout{10.5} is the clock time 10.5 seconds from the time the function was called.

> This function is useful when several synchronous operations are to be performed in a row, and all must finish within a certain time. Since the operations are performed sequentially, the same duration timeout cannot be used for all calls, but the same clock timeout can. This function converts a duration timeout to the (nearly) equivalent clock timeout, if the first of the synchronous operations is called immediately after the conversion is done.

## Import Data adap.Import{x}

> This function has been superseded by sys.imp.

## Listen adap.Listen{s;f}

Arguments and Result

> s is a service descriptor, as described in "Service Descriptors for Interprocess Connections". f is a callback function, as described in "Callback Functions and Events". The result is a service handle, as described in "Service Handles".

Definition

> This function is used to initialize listening partners, i.e., to set up the mechanism by which processes listen for partners attempting to establish connections. See "Interprocess Communication". The result is -1 if the function fails, which can happen, for example, if either argument is invalid. See "Service Descriptor Attributes regarding retries.

> The listening partner can set the port number to 0 in the argument s, in which case adap generates a valid port number. The listening partner can then get the assigned port number by executing adap.GetPort, but must broadcast this number to all potential partners.

Example

>     (ListenHandle)ûadap.Listen{
>                                (`name;`Test;
>                                 `host;`localhost;
>                                 `port;0;
>                                 `protocol;`A;
>                                 `retry;0);
>                                CallBackFunc};

## Modify Timer adap.ModifyTimer{h;s;d}

Arguments and Result

> h is the service handle of the timer, as described in "Service Handles". s is a symbol scalar, the name of the timer. d is a numeric scalar, the duration of the timer. The result is an integer scalar.

Definition

> This function changes the name (s) or the duration (d) of the timer with service handle h. The new duration is from the time when adap.ModifyTimer was called. The result is 1 if the timer is found and successfully modified, and 0 otherwise.

## Reset adap.Reset{h}

Argument and Result

> h is a service handle, as described in "Service Handles". The result is a scalar integer.

Definition

> If h is the service handle of an interprocess connection, this function closes the connection. This is a user-generated reset. It differs from a normal reset, in that a reset event is not generated. However, if this function is called by a connecting partner, the underlying system will then continually try to reconnect to the partner, just as it would for a normal reset. This function, which in practice would rarely be executed by the listening partner, has the same effect as adap.Close for that partner.

> If h is a timer, the timer event is reset to its original time duration, and no callback is generated.

> The result of this function is 1 if the service is successfully reset, i.e. if the service associated with it is found and reset, and 0 otherwise.

## Set Attribute Value adap.Has{h;x}

Arguments

> The left argument h is a service handle, as described in "Service Handles". The right argument is a nested vector.

Definition

> The right argument is an association list, i.e., a nested vector consisting of symbol, value pairs. The symbols are the names of service handle attributes. The effect of this function is to set these attributes, for the service handle h, to the values in the symbol, value pairs. The attributes applicable to h depend on the protocol for sending and receiving data with which h was established. A description of all the attributes follows.

> - list: A list of names, as symbols, of the attributes applicable to the service handle h. This attribute applies to all protocols.

> - rBufsize: The read buffer size for the A protocol; the default is 32K.

> - rEventMode: For the A protocol. If `single (the default), a separate read event occurs for each message received. If `burst, all pending messages from a service handle are gathered in a nested array (even if there is only one) for a single read callback. (Syncread is not affected; it always returns one message and does not enclose it in a nested array.) The purpose of burst mode is to allow an application to ensure that it is up to date. Burst mode can prevent a process with time-consuming read-event code from falling behind and it can obviate the execution of time-consuming dependency definitions. If an application nevertheless falls behind, that fact can be seen from the increasing numbers of messages at each read event. Cf. the read event type.

> - rPause: If 1, messages coming in on the read channel of the service handle h will be queued and no `sent events will be received; if 0, message processing proceeds normally, and in particular, any messages queued while the value was 1 will be read. This attribute applies to all protocols. Contact the A+ Development Group before setting this attribute.

> - rPriority: The value is an integer representing the relative priority of processing the read channel of the service handle h in the event loop of the A+ process. (Every time through the event loop, events associated with the event source of highest priority are processed first, then those associated with the event source of next highest priority, and so on.) Note: screen management events have priority 1024. Contact the A+ Development Group before setting this attribute.

> - rQueueStatus: This attribute is reference only, and its value and meaning are the same as those of the result of adap.ReadQueueStatus{h}. This attribute applies to all protocols.

> - wPause: Like rPause, except that when 1, sent messages are queued. This attribute applies to the A, raw, and ipc protocols.

> - wPriority: The value is an integer representing the relative priority of processing the send channel of the service handle h in the event loop of the A+ process. See rPriority. This attribute applies to the A, raw, and ipc protocols.

> - wQueueStatus: This attribute is reference only, and its value and meaning are the same as those of the result of adap.WriteQueueStatus{h}. This attribute applies to the A, raw, and ipc protocols.

> - wBufsize: The write buffer size for the A protocol; the default is 32K.

> - wNodelay: For the A protocol. Causes even tiny messages to be sent immediately; prevents their being accumulated with a view toward traffic reduction by batch transmission.

## Set Client Data adap.SetClientData{h;x}

Arguments and Result

> h is a service handle, as described in "Service Handles". x is any array that satisfies the conditions of the A protocol (see "Protocols for Sending and Receiving Data"). The result is 0.

Definition

> This function associates the array x with the service handle h. The array can be retrieved using adap.GetClientData. The client data x will no longer be accessible once the connection is closed.

> Client data is a convenient way to store auxiliary information about the communication handle. For example, if a client has several communication paths open to the same server, the client data could hold "instance" information.

## Set Timer adap.SetTimer{h;f;d}

Arguments and Result

> h is a symbol scalar, which is the name of the timer and of the event type in the callback. f is a callback function, as described in "Callback Functions and Events". d is a numeric scalar that represents the duration of the timer, in seconds; d can be fractional. The result is a service handle, as described in "Service Handles".

Definition

> This function sets the timer named by h to the duration specified by d. See "Interprocess Communication". The result is 0 if the function fails to establish a timer, which can happen, for example, if any of the arguments are invalid.

## Status of the Read Queue adap.ReadQueueStatus{h}

Arguments and Result

> The argument h is a service handle, as described in "Service Handles". The result is a two-element integer vector.

Definition

> The first element of the result is 1 if there is a message waiting to be read, and 0 otherwise. The second element is 1 if there is a message in the process of being read.

## Status of the Write Queue adap.WriteQueueStatus{h}

Arguments and Result

> The argument h is a service handle, as described in "Service Handles". The result is a two-element integer vector.

Definition

> The first element of the result contains the number of pending messages on the write queue. The second element is 1 if there is a message in the process of being sent, and 0 otherwise.

> If the write queue is empty (no pending messages), the result is 0 0. A result of 2 0 indicates two pending messages, while 1 1 indicates one pending message which has been partially sent.

> This function can be used in simple communication arrangements to keep track of the number of messages sent, rather than counting results of adap.Send and the callback data for sent events (see adap.Send, and the event types table).

## Synchronous Exchange adap.SyncXch{h;x;t}

Arguments and Result

> The argument h is a service handle, as described in "Service Handles". The argument x is the array to be the sent to the partner, which must satisfy the conditions of the A protocol (see "Protocols for Sending and Receiving Data"). The argument t is a timeout (see "Timeouts in Synchronous Communication"). The result is a nested vector.

Definition

> adap.SyncXch is an A+ cover function for synchronous communication in which the message x is sent with adap.Syncsend and, in response, a message is received using adap.Syncread. This is useful when only one message will be received for each message sent. If more than one message will be received for each message sent, then adap.Syncsend should be used, followed by a series of calls to adap.Syncread. The latter occurs, for example, when a server performing a long computation sends a series of status reports to the client.

> If adap.SyncXch fails due to a timeout in adap.Syncread, then the message was successfully sent, but the response was not received in the allotted time. If this function is subsequently called again for the same message, the message will be sent again.

> The first element of the result is either `error or `OK. If `OK, the second element contains the message from the partner. If it is `error, the first three elements are the result from either adap.Syncsend or adap.Syncread, and the fourth element is either `send or `read, to indicate which function it is.

## Synchronous Read adap.Syncread{h;t}

Arguments and Results

> The argument h is a service handle, as described in "Service Handles". The argument t is a timeout (see "Timeouts in Synchronous Communication"). The result is a three-element nested vector, or the Null.

Definition

> This functions waits for a message, i.e. array, to be received from the partner. The partner may send this array synchronously or asynchronously; if it was sent asynchronously, it must have been sent using the A protocol (see "Protocols for Sending and Receiving Data").

> If h is bad (not a valid service) the result is null. Otherwise, the result is a three-element enclosed vector. The first element is either `error or `OK, indicating success or failure. In case of an error, the second element is a symbol categorizing the error, and the third element is a system-generated character vector describing the error in more detail. Otherwise, the second element is the received message, and the third element is the Null.

## Synchronous Send adap.Syncsend{h;x;t}

Arguments and Result

> The argument h is a service handle, as described in "Service Handles". The argument x is the array to be the sent to the partner, which must satisfy the conditions of the A protocol (see "Protocols for Sending and Receiving Data"). The argument t is a timeout (see "Timeouts in Synchronous Communication"). The result is a three-element nested vector, or the Null.

Definition

> This function is for sending arrays to partners synchronously. This means that the message x, and any that are pending, are sent before the function terminates.

> If h is bad (not a valid service) the result is null. Otherwise,the result is a three-element nested vector. The first element is either `error or `OK, indicating success or failure. In case of an error, the second element is a symbol categorizing the error, and the third element is a system-generated character vector describing the error in more detail. In case of success, the second argument is the numbers of messages actually sent, and the third argument is the status of the write queue (see adap.WriteQueueStatus). Note that if there were previously sent messages in the write queue when adap.Syncsend was called, then the following are possible:

> - the number of messages sent can be greater than 1;

> - if the timeout expires then the number of messages sent can be greater than 0, although the current message x was not sent.