ToCDocOverviewCGDocRelNotesIndexPermutedIndex
Allegro CL version 6.1
Minimally revised

Remote Procedure Call support in Allegro CL

This document contains the following sections:

1.0 Introduction
   1.1 The package and module for RPC
2.0 A Simple RPC Example
3.0 Introduction to stream and datagram socket connections
4.0 Stream socket connections
   4.1 Connecting stream sockets
   4.2 Explicit port interface of stream sockets
   4.3 Declarative interface of stream sockets
   4.4 Callback style of stream sockets
5.0 Datagram socket connections
   5.1 Connecting datagram sockets
   5.2 Explicit port interface of datagram socket connections
   5.3 Declarative interface of datagram socket connections
   5.4 Callback style of datagram socket connections
6.0 Data Representation
   6.1 Uniqueness of Remote References
   6.2 Argument Conversions
   6.3 Operator Conversion
   6.4 Data Type Qualifiers
7.0 Error Tags
8.0 Gates
9.0 Examples


1.0 Introduction

The purpose of the RPC utility is to allow separate Lisp images to communicate with each other by remote procedure calls. This is accomplished by:

Although the interface is very symmetric, there is a need to distinguish between the roles of client and server. The server advertises the possibility of a connection, and the client connects to an advertising server. The distinction between client and server is significant when a connection is established (or re-established). Thus, a client image may connect on demand when a call is made, but a server image may call the client only when the client has made a connection. Once the connection is made, the actual calling protocol makes no reference to the distinction.

It is possible for the same image to be both client and server and each image in a set of communicating Lisp images may be both. But remote references to data are specific to a particular connection.


1.1 The package and module for RPC

All the symbols associated with RPC reside in the net.rpc package. RPC functionality is in the :aclrpc module. It is loaded into an image by evaluating (require :aclrpc).



2.0 A Simple RPC Example

For the sake of discussion in the following, we assume that two Lisp images, A and B are communicating. Image A is a server and B is a client.

Image A (server)                        Image B (client)

(multiple-value-setq (s p l es) 
  (define-rpc-server 'rpc-socket-server
     :home "lispA" :local-port 4326 
     :open :listener
     :connect-action :call
     :connect-function 
     #'(lambda (pt) (setf p pt))
     ;; :verbose verbose
     ))
(type-of s)
(null p)
(null es)   
(type-of l)               
                                        (multiple-value-setq (q ec)
					  (define-rpc-client 'rpc-socket-port
					  :home "lispB" :remote-port 4326 
					  :open t
					  ;; :verbose verbose
					  ))                      
					(type-of q)
					(null ec)
					(rpc-open-p q)
				        (with-remote-port (q)
					  (rcall 'print "Hello from B")
					  )
"Hello from B"

(rpc-open-p p)
(with-remote-port (p)
  (rcall 'print "Hello from A")         
  )
                                        "Hello from A"
					
					(rpc-close q :final t)

(rpc-open-p p)
(rpc-close s :stop :final)
                                        
(rpc-open-p :all)                       
                                        (rpc-open-p :all)


3.0 Introduction to stream and datagram socket connections

Stream connections are implemented on top of the operating system stream socket implementation. Stream sockets provide reliable two-way communication between two host processes. If a Lisp RPC call is made through a stream socket connection, the caller will receive a value or an error signal indicating that the call failed to complete.

If one Lisp host makes two RPC calls in succession to the same Lisp destination host (on the same stream socket connection), then the remote calls will be begun in the same order as they were sent.

Datagram connections are implemented on top of the operating system datagram socket implementation. The datagram protocol does not guarantee arrival of messages, nor does it preserve order.

Because of these semantics, callbacks hardly ever make sense and remote pointers are of dubious value since any manipulation of a remote pointer usually requires a call back to the home of the reference.

The following classes define the connection parameters and data transmission formats:



4.0 Stream socket connections

In the subsections of this section, we describe the Lisp API for Stream Socket connections.


4.1 Connecting stream sockets

The following classes define the connection parameters of stream socket connections.

The functions associated with connecting are:


4.2 Explicit port interface of stream sockets

The following operators are used once the port is established.


4.3 Declarative interface of stream sockets


4.4 Callback style of stream sockets

This RPC API supports three callback models:

Consider two lisp images A and B where A.i and B.j represent threads (Lisp processes) in A and B respectively.

Nested - Nested mode provides a continuity in dynamic environments in each running image.

Image A -- thread A.i Image B -- thread B.j
  • A begins thread A.i and
  • calls function g in B for the first time
  • B responds in (new) thread B.j
  • B.j calls function h in A
  • Call is handled in A.i on top of suspended call chain
  • h in A.i calls function m in B
  • Call is handled in B.j on top of suspended call chain
  • When m completes, B.j resumes wait for h to complete in A
  • When h completes, A.i goes back to wait mode
  • control returns to waiting B.j
  • When g completes, B.j terminates
  • and control returns to A.i
  • with nothing left unfinished.

Parallel - Parallel mode may the preferred mode for GUI event callbacks.This mode may be more prone to deadlocks than the nested mode.

Image A -- thread A.i Image B -- thread B.j Image A -- thread A.k Image B -- thread B.l
  • A begins thread A.i and
  • calls function g in B for the first time
  • B responds in (new) thread B.j
  • B.j calls function h in A
  • Call is handled in (new) thread A.k
  • h in A.k calls function m in B
  • Call is handled in (new) thread B.l
  • When m completes, B.l terminates (or gets recycled)
  • When h completes, A.k terminates (or gets recycled)
  • control returns to waiting B.j
  • When g completes, B.j terminates
  • and control returns to A.i
  • with nothing left unfinished.

Blocking - Blocking mode prevents recursive callbacks entirely. It requires careful programming to avoid deadlocks or errors.

Image A -- thread A.i Image B -- thread B.j Image A -- thread A.k
  • A begins thread A.i and
  • calls function g in B for the first time
  • B responds in (new) thread B.j
  • B.j calls function h in A
  • Call is handled in (new) thread A.k
  • A.k tries to call function m in B
  • An error is signaled in A.k because the path from A to B is still busy with the initial call from A.i to h in B.j

Each RPC port defines a default callback mode for calls through the port. The caller may override the default mode for an individual call.



5.0 Datagram socket connections

In this section and its subsections, we describe the Lisp API for Datagram Socket connections. The functions and methods have the same names as in the Stream Socket API but the semantics are sometimes different because of the nature of the protocol.

In addition to the indeterminate nature of message arrival, datagram connections exhibit several other unique characteristics:

Thus datagram connections do not exhibit the same symmetry as stream socket connections.


5.1 Connecting datagram sockets

The following classes define the connection parameters of datagram connections.

The following functions and methods are used for Datagram socket connecting.


5.2 Explicit port interface of datagram socket connections

The following functions and methods provide the interface to datagram socket connections.


5.3 Declarative interface of datagram socket connections

The following macros and function allow defining remote functions, methods, and classes.


5.4 Callback style of datagram socket connections

As said in Section 3.0 Introduction to stream and datagram socket connections, the datagram protocol does not guarantee arrival of messages, nor does it preserve the order of messages. Under these semantics, callbacks hardly ever make sense and remote pointers are of dubious value since any manipulation of a remote pointer usually requires a call back to the home of the reference.

Therefore, the datagram interface forces the callback mode to :blocking. Any mode arguments are ignored. Here is the description of blocking mode repeated from Section 4.4 Callback style of stream sockets.

Image A -- thread A.i Image B -- thread B.j Image A -- thread A.k
  • A begins thread A.i and
  • calls function g in B for the first time
  • B responds in (new) thread B.j
  • B.j calls function h in A
  • Call is handled in (new) thread A.k
  • A.k tries to call function m in B
  • An error is signaled in A.k because the path from A to B is still busy with the initial call from A.i to h in B.j


6.0 Data Representation

Data is transmitted between two RPC hosts in several ways:

The class rpc-remote-ref (with reader methods rr-home, rr-base, and rr-type) represents remote references in a Lisp image.

The operators rref and rpc-ref create explicit reference objects.


6.1 Uniqueness of Remote References

Remote references are relative to a particular connection. Consider a data item d passed from A to B on connection p as the remote reference r. If B passes r back to A on connection p, then A will see the pointer to d. Consider a second connection q between A and B, and a reference to d is passed to B on q as the remote reference s. If B passes s back to A on connection p, then B will see a remote reference, and not the pointer d.


6.2 Argument Conversions

The arguments to a remote call are passed by the following rules:

Note in addition, any data allocated in memory may be passed by reference.


6.3 Operator Conversion

The operator argument in rcall or rpc-invoke may be one of the following:

Any other argument will signal an error in the calling environment.


6.4 Data Type Qualifiers

This section describes the type argument to rref and rpc-ref. The symbol-mode, package-mode, symbol-name, and symbol-package arguments are also described.

The type argument can be any of the following qualifiers:

Qualifier Effect
:copy-maybe Create a transfer copy if possible. This is the default behavior for arguments and returned values.
:copy Like :copy-maybe
:copy-only Signal an error if the data cannot be passed by value.
:ref-maybe Create a remote reference if possible. For example, a float is normally passed by value, but may also be passed as a remote reference since it is a stored object in the Lisp image.
:ref Like :ref-maybe
:ref-only Signal an error if the data cannot be passed by reference. This is the case for fixnums, characters, and other immediate Lisp pointers.
:ignore This reference is being created in a call where the value will be ignored. Treated like :copy-maybe.
:one-way This reference is being created in a one-way call. Treated like :copy-maybe.

The following qualifiers make sense only when wrapping a value explicitly with rref.

:symbol Create a remote reference to a symbol. The data argument must be a symbol, but the symbol may be ignored if symbol-name and symbol-package keywords are passed.
:value Create a remote reference to the value of a symbol.
:function Create a remote reference to the function value of a symbol.
:class Create a remote reference to the class named by a symbol.
:boolean Create an immediate boolean value based on data.
:null The data argument must be nil.
:string The data argument must be a string.
:int The data argument must be coercible to an integer.
:single The data argument must be coercible to a single-float value.
:double The data argument must be coercible to a double-float value.
:byte The data argument must be coercible to an integer. It is truncated to a (signed-byte 8) value.
:short The data argument must be coercible to an integer. It is truncated to a (signed-byte 16) value.
:char The data argument must be a character.

When a symbol reference is created, the symbol-name, symbol-package, symbol-mode and package-mode arguments are used to control how the symbol is found in the remote environment.

The :symbol-mode argument controls how the name of a symbol is passed to the remote site, and how it is decoded there. The default mode is :read-case.

:symbol-mode symbol name string package name sent package used
:read-case ~S in *package* *package* decoded package
:absolute symbol-name symbol-package decoded package
:read-relative ~S in *package* "" (The empty string is sent. Any package argument supplied is ignored.) *package*
:string-equal-one symbol-name symbol-package decoded package

The :package-mode argument controls how the package name is sent and decoded. The default mode is :read-case.

:package-mode string sent package used
:read-case package-name Read the package name as a symbol from the passed string and call find-package with the result.
:absolute package-name Call find-package with the string sent.
:string-equal package-name Find a package matching the name with string-equal to the string sent.
:keyword "" The keyword package.

The default modes are appropriate for communication between two Lisps with similar package layouts and case modes. They may also be suitable for communication from a modern Lisp to an ANSI Lisp. Communication from an ANSI Lisp to a modern Lisp requires some care and the most reliable would be to use explicit symbol-name and symbol-package arguments.



7.0 Error Tags

Many RPC functions return a first value of nil if the operation fails. The second value is one of the following keywords to describe the reason for failure. Some functions return additional values (indicated by +) that add information about the failure.

Keyword Meaning and additional information
:rpc-err-open-server ropen - cannot call on server port
:rpc-err-server-timeout rpc-open-server - failed to get connection in time
:rpc-err-not-listening rpc-open-server - server is not listening
:rpc-err-accept + err rpc-open-server - error from socket accept
:rpc-err-connect-action connect-action is not :call :process or nil
:rpc-err-not-string ropen... - home name is not a string
:rpc-err-version + remote-vers ropen... - remote version mismatch
:rpc-err-duplicate ropen... - home name is duplicate in remote host
:rpc-err-not-found ropen...(re-connect) - home name not found
:rpc-err-limit ropen... - remote host has reached connection limit
:rpc-err-max ropen... - remote host saturated (temp)
:rpc-err-home-busy ropen...(connect) - home is already in use (connected or waiting for re-connect)
:rpc-err-re-connect ropen...(re-connect) - home is already in use (connected)
:rpc-err-refused ropen...(re-connect) - refused: bad gen or remote
:rpc-err-connect + code ropen or rpc-open-client...- the first byte received by the server was not one of the two expected values (:connect or :re-connect); code is the actual numeric value of the byte.
:rpc-err-connected-error + code ropen...- failed to get :connected confirmation
:rpc-err-not-client from rpc-open-client
:rpc-err-not-idle from rpc-open-client
:rpc-err-already-open from rpc-open-client
:rpc-err-streams from rpc-open-client - stream not consistent
:rpc-err-connect-failed + err ropen... - connect failed, err from remote host
:rpc-err-connect-failed + rhome ropen... - connect failed, duplicate connect attempt
:rpc-err-connect-failed + sockerr ropen... - connect failed with sockerr
:rpc-err-connect-failed + long ropen... - connect failed after n attempts
:rpc-err-re-connect-failed + rhome ropen... - duplicate re-connect attempt
:rpc-err-connerr + err ropen... - connect failed, err from remote host
:rpc-err-bad-connect + code ropen... - protocol garbled (expected :confirm-connect or :conn-error)
:rpc-err-begin-failed + begin-err... rpc-open-server
:rpc-err-begin-state + state rpc-begin
:rpc-err-begin-gate
:rpc-err-begin-fail + state + flag
:rpc-err-begin-timeout + port
:rpc-err-req-dest rpc-send-request - destination thread unknown
:rpc-err-invoke-dest rcall... - destination thread unknown
:rpc-err-user + ~A request/invoke - error in remote application code
:rpc-err-socket-error + sockerr rpc-open-server - error from socket call


8.0 Gates

Locking and synchronization are major concerns in a distributed application. The following macros and functions extend the usefulness of multiprocessing gate objects (see Gates (both models) in multiprocessing.htm).



9.0 Examples

We include two simple examples of RPC coding in examples/aclrpc/ subdirectory of the Allegro directory. The file rpc-nameserve.cl contains a simple nameserver implemented with datagram calls.

The file rpc-inspect.cl contains an extension to the ACL console inspector. The extension uses RPC calls to display the components and contents of remote data objects.

The server image is activated by evaluating (server) and the client image is activated by evaluating (client).

The client function sets the variable *var* in the server image. The variable is set to a remote reference to a list of objects in the client image.

The following annotated typescript shows how the variable *var* is examined from the console of the server image.

cl-user(23): *var*
#<rpc-ref inspectee:pointer#161529357/1001/"cons">
cl-user(24): :i *
rpc-remote-ref @ #x20e518aa = #<rpc-ref inspectee:pointer#161529357/1001/"cons">
   0 RefType ------> The symbol :pointer
   1 RemoteHome ---> A simple-string (9) "inspectee"
   2 RemoteType ---> A simple-string (4) "cons"
   3 RemoteParts --> #<remote-field-defs @ #x20e5c02a>

As we inspect the remote reference in *var*, the inspector extension shows the information that is available without leaving the local image. This is a design decision in the inspector extension - remote information is retrieved only on demand to avoid potentially extensive delays.

cl-user(25): :i 3
remote-field-defs @ #x20e5c1e2 = #<remote-field-defs @ #x20e5c1e2>
   0 RemoteObject -> #<rpc-ref inspectee:pointer#161529357/1001/"cons">
   1 Size ---------> fixnum 5 [#x00000014]
   2 LookingAt ----> (0 4), a proper list with 2 elements
   3 nil ----------> #<rpc-ref inspectee:pointer#161529357/1002/"myclass">
   4 nil ----------> #<rpc-ref inspectee:pointer#161529357/1003/"mystruct">
   5 nil ----------> #<rpc-ref inspectee:pointer#161529357/1004/"t">
   6 nil ----------> #<rpc-ref inspectee:pointer#161529357/1005/"t">
   7 nil ----------> (1 2 3 4 . 5), a dotted list with 4 elements

If we select the RemoteParts field, the inspector goes to the inspectee image and retrieves the top-level components of the list. Line 1 shows that we are looking at a remote object with 5 components. Line 2 shows that we are looking at components 0 through 4, all the components in this case.

cl-user(26): :i 3
rpc-remote-ref @ #x20e60a52 = #<rpc-ref inspectee:pointer#161529357/1006/"myclass">
   0 RefType ------> The symbol :pointer
   1 RemoteHome ---> A simple-string (9) "inspectee"
   2 RemoteType ---> A simple-string (7) "myclass"
   3 RemoteParts --> #<remote-field-defs @ #x20e60eca>

As we select line 3 (or component 0), we again see a remote reference.

cl-user(27): :i 3
remote-field-defs @ #x20e61042 = #<remote-field-defs @ #x20e61042>
   0 RemoteObject -> #<rpc-ref inspectee:pointer#161529357/1006/"myclass">
   1 Size ---------> fixnum 2 [#x00000008]
   2 LookingAt ----> (0 1), a proper list with 2 elements
   3 a ------------> fixnum 123 [#x000001ec]
   4 b ------------> fixnum 455 [#x0000071c]

When we select the RemoteParts field, we see the slot names and the values.

cl-user(28): :i -
rpc-remote-ref @ #x20e60a52 = #<rpc-ref inspectee:pointer#161529357/1006/"myclass">
   0 RefType ------> The symbol :pointer
   1 RemoteHome ---> A simple-string (9) "inspectee"
   2 RemoteType ---> A simple-string (7) "myclass"
   3 RemoteParts --> #<remote-field-defs @ #x20e62eb2>
cl-user(29): :i -
remote-field-defs @ #x20e5c1e2 = #<remote-field-defs @ #x20e5c1e2>
   0 RemoteObject -> #<rpc-ref inspectee:pointer#161529357/1001/"cons">
   1 Size ---------> fixnum 5 [#x00000014]
   2 LookingAt ----> (0 4), a proper list with 2 elements
   3 nil ----------> #<rpc-ref inspectee:pointer#161529357/1007/"myclass">
   4 nil ----------> #<rpc-ref inspectee:pointer#161529357/1008/"mystruct">
   5 nil ----------> #<rpc-ref inspectee:pointer#161529357/1009/"t">
   6 nil ----------> #<rpc-ref inspectee:pointer#161529357/1010/"t">
   7 nil ----------> (1 2 3 4 . 5), a dotted list with 4 elements
cl-user(30): :i 4
rpc-remote-ref @ #x20e6698a = #<rpc-ref inspectee:pointer#161529357/1011/"mystruct">
   0 RefType ------> The symbol :pointer
   1 RemoteHome ---> A simple-string (9) "inspectee"
   2 RemoteType ---> A simple-string (8) "mystruct"
   3 RemoteParts --> #<remote-field-defs @ #x20e66e3a>

Returning to the initial object contents, we select line 4, or element 1 of the remote list.

cl-user(31): :i 3
remote-field-defs @ #x20e66fb2 = #<remote-field-defs @ #x20e66fb2>
   0 RemoteObject -> #<rpc-ref inspectee:pointer#161529357/1011/"mystruct">
   1 Size ---------> fixnum 16 [#x00000040]
   2 LookingAt ----> (0 9), a proper list with 2 elements
   3 a ------------> The symbol nil
   4 b ------------> The symbol nil
   5 c ------------> The symbol nil
   6 d ------------> The symbol nil
   7 e ------------> The symbol nil
   8 f ------------> The symbol nil
   9 g ------------> The symbol nil
  10 h ------------> The symbol nil
  11 i ------------> The symbol nil
  12 j ------------> The symbol nil
  13 MoreParts ----> #<remote-field-defs @ #x20e71622>

As we select the RemoteParts field, we see the first 10 slots of a structure with 16 slots. We can see the remaining slots by selecting the MoreParts field on line 13.

cl-user(32): :i -
rpc-remote-ref @ #x20e6698a = #<rpc-ref inspectee:pointer#161529357/1011/"mystruct">
   0 RefType ------> The symbol :pointer
   1 RemoteHome ---> A simple-string (9) "inspectee"
   2 RemoteType ---> A simple-string (8) "mystruct"
   3 RemoteParts --> #<remote-field-defs @ #x20e71842>
cl-user(33): :i -
remote-field-defs @ #x20e5c1e2 = #<remote-field-defs @ #x20e5c1e2>
   0 RemoteObject -> #<rpc-ref inspectee:pointer#161529357/1001/"cons">
   1 Size ---------> fixnum 5 [#x00000014]
   2 LookingAt ----> (0 4), a proper list with 2 elements
   3 nil ----------> #<rpc-ref inspectee:pointer#161529357/1012/"myclass">
   4 nil ----------> #<rpc-ref inspectee:pointer#161529357/1013/"mystruct">
   5 nil ----------> #<rpc-ref inspectee:pointer#161529357/1014/"t">
   6 nil ----------> #<rpc-ref inspectee:pointer#161529357/1015/"t">
   7 nil ----------> (1 2 3 4 . 5), a dotted list with 4 elements
cl-user(34): :i 5
rpc-remote-ref @ #x20e75572 = #<rpc-ref inspectee:pointer#161529357/1016/"t">
   0 RefType ------> The symbol :pointer
   1 RemoteHome ---> A simple-string (9) "inspectee"
   2 RemoteType ---> A simple-string (14) "(array t (57))"
   3 RemoteParts --> #<remote-field-defs @ #x20e75a6a>
cl-user(35): :i 3
remote-field-defs @ #x20e75be2 = #<remote-field-defs @ #x20e75be2>
   0 RemoteObject -> #<rpc-ref inspectee:pointer#161529357/1016/"t">
   1 Size ---------> fixnum 57 [#x000000e4]
   2 LookingAt ----> (0 9), a proper list with 2 elements
   3 nil ----------> #<rpc-ref inspectee:pointer#161529357/1017/"cons">
   4 nil ----------> #<rpc-ref inspectee:pointer#161529357/1018/"cons">
   5 nil ----------> #<rpc-ref inspectee:pointer#161529357/1019/"cons">
   6 nil ----------> #<rpc-ref inspectee:pointer#161529357/1020/"cons">
   7 nil ----------> #<rpc-ref inspectee:pointer#161529357/1021/"cons">
   8 nil ----------> #<rpc-ref inspectee:pointer#161529357/1022/"cons">
   9 nil ----------> #<rpc-ref inspectee:pointer#161529357/1023/"cons">
  10 nil ----------> #<rpc-ref inspectee:pointer#161529357/1024/"cons">
  11 nil ----------> #<rpc-ref inspectee:pointer#161529357/1025/"cons">
  12 nil ----------> #<rpc-ref inspectee:pointer#161529357/1026/"cons">
  13 MoreParts ----> #<remote-field-defs @ #x20e7cf1a>
cl-user(36): :i 13
remote-field-defs @ #x20e7d0a2 = #<remote-field-defs @ #x20e7d0a2>
   0 RemoteObject -> #<rpc-ref inspectee:pointer#161529357/1016/"t">
   1 Size ---------> fixnum 57 [#x000000e4]
   2 LookingAt ----> (10 19), a proper list with 2 elements
   3 nil ----------> #<rpc-ref inspectee:pointer#161529357/1027/"cons">
   4 nil ----------> #<rpc-ref inspectee:pointer#161529357/1028/"cons">
   5 nil ----------> #<rpc-ref inspectee:pointer#161529357/1029/"cons">
   6 nil ----------> #<rpc-ref inspectee:pointer#161529357/1030/"cons">
   7 nil ----------> #<rpc-ref inspectee:pointer#161529357/1031/"cons">
   8 nil ----------> #<rpc-ref inspectee:pointer#161529357/1032/"cons">
   9 nil ----------> #<rpc-ref inspectee:pointer#161529357/1033/"cons">
  10 nil ----------> #<rpc-ref inspectee:pointer#161529357/1034/"cons">
  11 nil ----------> #<rpc-ref inspectee:pointer#161529357/1035/"cons">
  12 nil ----------> #<rpc-ref inspectee:pointer#161529357/1036/"cons">
  13 MoreParts ----> #<remote-field-defs @ #x20e843ea>
cl-user(37): :i 13
remote-field-defs @ #x20e84572 = #<remote-field-defs @ #x20e84572>
   0 RemoteObject -> #<rpc-ref inspectee:pointer#161529357/1016/"t">
   1 Size ---------> fixnum 57 [#x000000e4]
   2 LookingAt ----> (20 29), a proper list with 2 elements
   3 nil ----------> #<rpc-ref inspectee:pointer#161529357/1037/"cons">
   4 nil ----------> #<rpc-ref inspectee:pointer#161529357/1038/"cons">
   5 nil ----------> #<rpc-ref inspectee:pointer#161529357/1039/"cons">
   6 nil ----------> #<rpc-ref inspectee:pointer#161529357/1040/"cons">
   7 nil ----------> #<rpc-ref inspectee:pointer#161529357/1041/"cons">
   8 nil ----------> #<rpc-ref inspectee:pointer#161529357/1042/"cons">
   9 nil ----------> #<rpc-ref inspectee:pointer#161529357/1043/"cons">
  10 nil ----------> #<rpc-ref inspectee:pointer#161529357/1044/"cons">
  11 nil ----------> #<rpc-ref inspectee:pointer#161529357/1045/"cons">
  12 nil ----------> #<rpc-ref inspectee:pointer#161529357/1046/"cons">
  13 MoreParts ----> #<remote-field-defs @ #x20e8b8ba>

To see the components of a very large object, we need to select the MoreParts field several times.

cl-user(38): :i 0
rpc-remote-ref @ #x20e75572 = #<rpc-ref inspectee:pointer#161529357/1016/"t">
   0 RefType ------> The symbol :pointer
   1 RemoteHome ---> A simple-string (9) "inspectee"
   2 RemoteType ---> A simple-string (14) "(array t (57))"
   3 RemoteParts --> #<remote-field-defs @ #x20e8bc82>

We can return to the initial reference of the large object by selecting the RemoteObject field on line 0. This avoids the need to climb back through multiple MoreParts steps.


Copyright (c) 1998-2001, Franz Inc. Berkeley, CA., USA. All rights reserved.
Documentation for Allegro CL version 6.1 update # 1. This page has had minimal revisions.
Created 2001.12.15.

ToCDocOverviewCGDocRelNotesIndexPermutedIndex
Allegro CL version 6.1
Minimally revised