Remote Procedure Calls (RPCs)

When a VTScada subroutine executes, all other statement execution within the thread that is running the subroutine is suspended. The RPC subroutine is run on the RPC Manager’s thread. This is a deliberate behavior, ensuring that only one RPC subroutine is ever running within an instance of VTScada. This enables the RPC subroutine to access three important variables, which RPC Manager maintains:

  • CurSocketNode - the MachineNode object that exists for the machine that issued the RPC. A MachineNode exists for every machine that an instance of VTScada can communicate with, including the local machine. Note that, before support for multi-homed machines was introduced, this variable did indeed refer to the SocketNode from which an RPC request had been received. Its name has not been changed, to preserve compatibility with existing applications.
  • CurSessionID - the opaque Session ID of the application instance that issued the RPC .
  • CurSourceAppGUID - the GUID of the application that issued the RPC .

The contents of these three variables are valid only for the duration of the execution of the RPC subroutine. When the RPC subroutine returns, these variables are deliberately invalidated and then set to new contents for the next RPC subroutine execution. If you wish to retain the contents of either of these variables, you must make a copy during execution of the RPC subroutine.

If the RPC subroutine is not written as a launched module rather than as a subroutine,  then RPC Manager will launch the module, but access to the above variables is not permitted. A module launched in this way will be launched on the thread of the context into which the module is launched (normally the service’s thread).

You should treat RPC subroutines in the same manner as one would treat interrupt service routines. Execution of an RPC subroutine suspends all other RPC activity on the machine executing the subroutine. Therefore, if there is time-consuming work to be performed, it is preferable to have the RPC subroutine launch a worker module into an appropriate context, passing the contents of CurSocketNode and CurSessionID if required, as parameters. For example:

{==================== SampleRPCLaunch ========================}
{ This subroutine is called via RPC and launches off a worker }
{ module to do some time-consuming work.                    }
{=============================================================}
(
  SomeParam           { Parameter to the RPC subroutine             };
)
[
  DoTheWork Module;
]

Only [
  If 1;
  [
    {** Pass the CurSessionID & CurSocketNode to the launched module **}
    DoTheWork(SomeParam, \RPCManager\CurSocketNode, \RPCManager\CurSessionID);
    Return(0);
  ]
]

<
{============== SampleRPCLaunch\DoTheWork ===================}
{============================================================}
DoTheWork
(
  SomeParam             { Same as RPC subroutine                      };
  ClientSocketNode      { Client socket node at time of starting      };
  ClientSID             { Calling client's session ID                 };
)

Init [
  If 1 Main;
  [
    { Typical initialization code here }
  ]
]

Main [
  { Whatever code performs the time consuming work }
  If Finished;
  [
    Slay(Self(), 0);  { Terminate myself }
  ]
]

{ End of SampleRPCLaunch\DoTheWork }
>

Cross-Application RPC