Skip to content

State and Access Control

Earlier, we have seen how shared variable state and access controls are used to ensure effective communication between two APL tasks. How do these concepts apply in the DDE environment when APL is using shared variables to communicate via DDE with both other APL workspaces, and with non-APL applications?

The initial state of a shared variable on the completion of sharing depends upon whether your variable is a server or a client. If it is a server, the initial state vector is (1 0 1 0) which means that you have set (and know) the value, but your partner has yet to use it. If the variable is acting as a client, the initial state vector is (0 1 0 1). This implies that your partner has set the value but you have yet to use it.

As your partner can be a non-APL application which does not share the concepts of set and use, it is necessary to define a rule or set of rules from which APL can reasonably infer such actions.

During a DDE conversation, the physical transfer of data from one application to another is achieved using DDE DATA messages. When a DATA message is sent, the receiving task normally returns an ACK (acknowledgement) message. APL uses the DATA and ACK messages to control Shared Variable access.

When an assignment is made to a shared variable, APL sends a DATA message to the second process. When it receives back an ACK message, APL infers that this means that the partner has used the variable. When APL receives a DATA message from the other process it infers that the partner has set the variable. However, it only responds with an ACK message when the new value of the variable is referenced by the workspace.

Let's see what this means if two APL workspaces are involved.

Server Workspace Client Workspace
   
Make general offer  
      X←42  
      'DDE:' ⎕SVO 'X'  
1  
      ⎕SVS 'X'  
0 0 0 0 ⍝ No partner  
      ⎕SVC 'X'  
0 0 0 0 ⍝ No access ctl  
   
  Make specific offer
  'DDE:DYALOG|SERVER'⎕SVO'X'
  <--- initiate ---
ack --->  
  <--- please advise on change
ack --->  
  2  ⍝ Offer accepted
      ⎕SVS 'X'       ⎕SVS 'X'
1 0 1 0⍝ I know, not he 0 1 0 1⍝ He knows, I don't
  Client requests data
        Y ← X
  <--- req ---
--- data (42) --->  
  <--- ack ---
      ⎕SVS 'X'       ⎕SVS 'X'
0 0 1 1⍝ We both know 0 0 1 1⍝ We both know
Server changes data  
      X ← 20  
--- data has changed -->  
  <--- ack ---
      ⎕SVS 'X'       ⎕SVS 'X'
1 0 1 0 ⍝ I know, not he 0 1 0 1 ⍝ He knows, I don't
  Client requests data
        Y ← X
  <--- req ---
--- data (20) --->  
  <--- ack ---
      ⎕SVS 'X'       ⎕SVS 'X'
0 0 1 1 ⍝ We both know 0 0 1 1 ⍝ We both know

As you can see, this has the desired effect, namely that an APL workspace sets the value of a shared variable by assignment to it and uses it by reference to it. The mechanism of using the DATA and ACK messages to imply set and use also works with non-APL applications which do not (in general) support these concepts.

Access control between two APL workspaces is imposed by each workspace acting independently. Whenever either workspace changes its ⎕SVC, the information is transmitted to the other. Thus both workspaces maintain their own copy of the effective access control vector upon which to base decisions.

Server Workspace Client Workspace
No access control No access control
      ⎕SVC 'X'       ⎕SVC 'X'
0 0 0 0 ⍝ No access ctl 0 0 0 0 ⍝ No access ctl
  Client makes multiple requests for data
         Y←X
         Y←X
Server can set several times  
      X←30  
      X←40  
Set access control  
      1 0 0 1 ⎕SVC 'X'  
--- change in ⎕SVC -->  
      ⎕SVC 'X'       ⎕SVC 'X'
1 0 0 1 ⍝ I cannot set
    until he has used; he cannot
    use until I have set
0 1 1 0 ⍝ He cannot set
    until I have used. 
    I cannot use until he has set
  Client requests data
        Y ← X
  <--- req ---
  (hangs waiting for data)
Server changes data  
      X ← 30  
--- data (30) --->  
  <--- ack ---
        Y ⍝ data received
  30
Server changes data  
      X ← 40  
--- data has changed --->  
  <--- ack ---
Server tries to change data again  
      X ← 50  
--- data has changed --->  
(assignment hangs waiting for ack)  
        Y ← X ⍝ use data
  <--- req ---
--- data (40) --->  
  <--- ack ---
      X ⍝ assignment done       Y ⍝ data received
50 40

Where the second process is a non-APL application, the effective access control vector is maintained only by the APL task and access control can only be imposed by APL. At first sight, it may seem impossible for APL to affect another application in this way, and indeed there are severe limitations in what APL can achieve. Nevertheless, effective access control is possible in the case when it is desirable to inhibit the partner from setting the value twice without an intervening use by the APL task.

This is simply achieved by withholding the ACK message. Thus if APL receives a DATA message from its partner at a time when a set by the partner is inhibited, APL registers the new value but withholds the acknowledgement. Only when the inhibitor is removed will APL respond with an ACK. (Users with DDESPY will observe that this is actually implemented by APL re-transmitting the DATA message to itself when the inhibitor is removed).

Assuming that the second application waits for the acknowledgement before proceeding, this will cause the desired synchronisation. Naturally, this cannot be entirely guaranteed because APL has no direct control over a non-APL program. Indeed, when an application transmits a DATA message, it can include a flag to indicate that an acknowledgement is neither expected nor required. In these circumstances, APL is powerless to impose any access control.

Note that APL does not (and cannot) have any control over successive internal references to the data by a non-APL application.

The rule for establishing your partner's initial ⎕SVC is as follows:

  • If the DDE link is a warm link, your partner's ⎕SVC is initially (0 0 0 0).
  • If the DDE link is instead a hot link, your partner's ⎕SVC is initially (1 0 0 1).

This works in practice as follows:

Server = APL, Client = APL

You made a general offer which has been accepted by another APL workspace. For example:

      'DDE:' ⎕SVO 'DATA'

Two APL tasks always use a warm DDE link. Therefore, initially, both ⎕SVCs are (0 0 0 0). Control is (optionally) imposed by both partners subsequently setting ⎕SVC.

Server = APL, Client = another application

You made a general offer which has been accepted by another application. For example:

      'DDE:' ⎕SVO 'DATA'

The client application establishes the strength of the link (warm or hot). If it is a warm link, the initial value of the client's ⎕SVC is (0 0 0 0) and, as the client has no means to change it itself, control may only be imposed by the server APL task. If the client establishes a hot link, its initial ⎕SVC is (1 0 0 1). As it has no means to change it, and as the APL server task cannot (by definition) change it, the client's ⎕SVC retains this setting for the duration of the conversation. (1 0 0 1) means that both partners are inhibited from setting the value of the shared variable twice in a row without an intervening use (or set) by the other. Given that the other application has requested a hot link (give me the value every time it changes) it is reasonable to assume that the application does not want to miss any values and will happily accept new data every time it is changed.

Server = another application, Client = APL

You made a specific offer to another application. For example:

      'DDE:EXCEL|SHEET1' ⎕SVO 'DATA R1C1:R3C4'

In this case, APL as the client will request a warm DDE link. If the server fails to agree to this request, APL will ask for the current data value and, whether or not the server responds, will not establish a permanent link. Thus the only possibility for a permanent connection is a warm link. This in turn means that the server's ⎕SVC will be (0 0 0 0). Furthermore, as the server has no means to change it, it's ⎕SVC will remain (0 0 0 0) for the duration of the conversation. Control is therefore imposed solely by APL.

Terminating a Conversation

A DDE conversation is terminated by "un-sharing" the variable. This can be done explicitly using ⎕EX or ⎕SVR. It is also done automatically when you exit a function in which a shared variable is localised.