Apple, Inc. v. Motorola, Inc. et al
Filing
12
AMENDED COMPLAINT for Patent Infringement against Motorola Mobility, Inc., Motorola, Inc., filed by Apple, Inc.. (Attachments: #1 Exhibit A - '949 patent, #2 Exhibit B - '002 patent, #3 Exhibit C - '315 patent, #4 Exhibit D - RE '486 patent, #5 Exhibit E - '354 patent, #6 Exhibit F - '263 patent, #7 Exhibit G - '983 patent, #8 Exhibit H - '705 patent, #9 Exhibit I - '647 patent, #10 Exhibit J - '852 patent, #11 Exhibit K - '131 patent, #12 Exhibit L - '337 patent, #13 Exhibit M - '867 patent, #14 Exhibit N - '721 patent, #15 Exhibit O - '599 patent) (Peterson, James) [Transferred from Wisconsin Western on 12/1/2011.]
EXHIBIT N
111111111111111111111111111111111111111111111111111111111111111111111111111
US005481721A
United States Patent
[11]
Serlet et al.
[54]
METHOD FOR PROVIDING AUTOMATIC
AND DYNAMIC TRANSLATION OF OBJECT
ORIENTED PROGRAMMING
LANGUAGE-BASED MESSAGE PASSING
INTO OPERATION SYSTEM MESSAGE
PASSING USING PROXY OBJECTS
[75]
Inventors: Bertrand Serlet; Lee Boynton, both of
Palo Alto; Avadis Tevanian, Mountain
View, all of Calif.
[73]
Assignee: NeXT Computer, Inc., Redwood City,
Calif.
[21]
Appl. No.: 332,486
[22]
Filed:
Patent Number:
[45]
[19]
Date of Patent:
OTHER PUBLICATIONS
Bennet, 1. K., "The design and implementation of Distributed Smalltalk", SIGPLAN Notices, vol. 22, No. 12, pp.
318-320, OOPSLA '87 Proceedings, Dec. 1987.
McCullough, P. L., "Transparent Forwarding: First Steps",
SIGPLAN Notices, vol. 22, No. 12, pp. 331-341, OOPSLA
'87 Proceedings, Dec. 1987.
Shapiro, M., ''The Design of a Distributed Object-Oriented
Operating System For Office Applications", ESPRIT '88.
Putting the Technology to Use Proceedings of the 5th
Annual ESPRIT Conference, pp. 1020-1027, vol. 2, Nov.
1988.
Primary Examiner-Kevin A. Kriess
Attorney, Agent, or Firm-Hecker & Harriman
Oct. 31, 1994
[57]
Related U.S. Application Data
[63]
Continuation of Ser. No. 731,636, Jul. 17, 1991, abandoned.
[51]
[52]
Int. Cl. 6
U.S. Cl.
[58]
Field of Search
[56]
5,481,721
Jan. 2, 1996
G06F 9/44
39SnOO; 364/DIG. 1;
.•....••••.••....•...................•.•••••••••.•••••••
364/280; 364/284.3; 364/284
3951700, 650;
364/DIG. 1, DIG. 2
References Cited
U.S. PATENT DOCUMENTS
5,060,150 10/1991 Simor
5,230,051 7/1993 Quan
5,305,461 4/1994 Feigenbaum et aI
The present invention provides a method and apparatus for
the distribution of objects and the sending of messages
between objects that are located in different processes.
Initially, a "proxy" object is created in the same process as
a sender object. This proxy acts as a local receiver for all
objects in the local program. When the proxy receives a
message, the message is encoded and transmitted between
programs as a stream of bytes. In the remote process, the
message is decoded and executed as if the sender was
remote. The result follows the same path, encoded, transmitted, and then decoded back in the local process. The
result is then provided to the sending object.
3641200
395/700
395/775
LOCAL
r-
ABSTRACT
24 Claims, 6 Drawing Sheets
901
906
REMOTE
r-
902
909
904
907
9~
914
913
~
o
9125J
u.s. Patent
/
,.-
5,481,721
Sheet 1 of 6
Jan. 2, 1996
101
CLASS 1
METHODS A, B, C
~03
INSTANCE
METHODS A, B, C
'J4
r-----L..---L----,
SUBCLASS 1.1
INSTANCE
METHODS A, B, C, E I - - METHODS A, B, C, E
FIG.
1 PRIOR ART
I
II
DELEGATE
201
OBJECT A
1-------.
OBJECT B
MESSAGE
MESSAGE
~
DELEGATE
FIG. 2
OBJECT C
417
418
CRT
FIG. 4
VIDEO MUX
AND SHIFTERS
413
416
415
414
CPU
MAIN MEMORY
VIDEO MEMORY
419
MOUSE
410
411
MASS STORAGE
412
u.s. Patent
Jan. 2, 1996
5,481,721
Sheet 2 of 6
FIG. 3A
LOCAL
r-
901
REMOTE
906
r-
902
904
907
909
905
FIG. 38
LOCAL
r-
901
REMOTE
906
902
909
904
907
ARGUMENT =
905
r-
u.s. Patent
Jan. 2, 1996
5,481,721
Sheet 3 of 6
FIG. 3C
LOCAL
r
901
906
REMOTE
r
902
909
904
907
ARGUMENT =
905
911
EXECUTE
914
913
o
912.xJ
u.s. Patent
Jan. 2, 1996
5,481,721
Sheet 4 of 6
FIG. 5
A SELECTOR MESSAGE
TO OBJECT B
DECODE RESULT
511
ENCODE RESULT
AND TRANSMIT
501
503
510
IMPLEMENTATION
EXIST IN OBJECT B
?
YES
INVOKE FORWARD::
EXECUTE METHOD
AND GENERATE RESULT
DECODE AND PROVIDE
TO DESTINATION OBJEC
ENCODE MESSAGE
AND TRANSMIT
507
504
LOCATE OBJECT TO
RESPOND TO A
SELECTOR MESSAGE
505
509
508
YES
506
513
u.s. Patent
5,481,721
Sheet 5 of 6
Jan. 2, 1996
F/G. 6 PRIOR ART
LOCAL MACHINE
6~2
601-.......
r - PROXY OBJECT
603
MESSAGE DESTINED FOR
REMOTE OBJECT
FORWARDED
MESSAGE
1
I
--
04
5
606
I
-'-
T
RESULT
OBJECT
REMOTE OBJECT
605
REMOTE MACHINE
F/G. 7 PRIOR ART
LOCAL MACHINE
704
702
703
PROXY OBJECT I--~--...I POLICYMAKER
TRANSPORTER
ROOM
MESSAGE DESTINED FOR
REMOTE OBJECT
I
705
706
708
715
707
T
710
\
RECONSTRUCTED MESSAGE
TRANSPORTER
ROOM
REMOTE OBJECT
/
714
711
712./
606
I
I
POLICYMAKER
REMOTE MACHINE
7~
1--713
u.s. Patent
5,481,721
Sheet 6 of 6
Jan. 2, 1996
FIG. 8A
806
804
MESSAGE
..
!,.
RESULT \
805
802
803
FIG. 88
LOCAL
r
801
PRIOR ART
REMOTE
r
804
802
808
807
5,481,721
1
2
METHOD FOR PROVIDING AUTOMATIC
AND DYNAMIC TRANSLATION OF OBJECT
ORIENTED PROGRAMMING
LANGUAGE-BASED MESSAGE PASSING
INTO OPERATION SYSTEM MESSAGE
PASSING USING PROXY OBJECTS
behavior from other objects.
The inheritance hierarchy is the hierarchy of classes
defined by the arrangement of superclasses and subclasses.
Except for the root classes, every class has a superclass, and
any class may have an unlimited number of subclasses. Each
class inherits from those classes above it in the hierarchy.
Thus, a superclass has the ability to pass its characteristics
(methods and instance variables) onto its subclasses.
FIG. 1 is a block diagram that illustrates inheritance.
Class 1 (generally indicated by block 101) defines a class of
objects that have three methods in common, namely, A, B
and C. An object belonging to a class is referred to as an
"instance" of that class. An example of an instance of class
1 is block 102. An instance such as instance 102 contains all
the methods of its parent class. Block 102 contains methods
A, Band C.
As discussed, each class may also have subclasses, which
also share all the methods of the class. Subclass 1.1 (indicated by block 103) inherits methods A, B and C and defines
an additional method, E. Each subclass can have its own
instances, such as, for example, instance 104. Each instance
of a subclass includes all the methods of the subclass. For
example, instance 104 includes methods A, B, C and E of
subclass 1.1.
Not all object oriented programming languages permit
new methods to be added per instance. For, example, in
Objective C, an instance can not have methods that are not
contained in its parent class.
A disadvantage of an inheritance-based, object-oriented
programming language is object size. Because each subclass
must, by definition, include all methods of its parent class
and super classes, instances are larger at the bottom of the
inheritance hierarchy.
Object-oriented programming languages that utilize the
class/instance/inheritance structure described above implement a set-theoretic approach to sharing knowledge. This
approach is used in object-oriented programming languages,
such as Simula, SmallTalk, Flavors and Loops.
BACKGROUND OF THE PRESENT
INVENTION
This is a continuation of application Ser. No. 07/731,636
filed Jul. 17, 1991, now abandoned.
10
FIELD OF THE INVENTION
This invention relates to the field of object-oriented
programming and distributed computing.
15
BACKGROUND ART
Object-oriented programming is a method of creating
computer programs by combining certain fundamental
building blocks, and creating relationships among and
between the building blocks. The building blocks objectoriented programming systems are called "objects." An
object is a programming unit that groups together a data
structure (instance variables) and the operations (methods)
that can use or affect that data. Thus, an object consists of
data and one or more operations or procedures that can be
performed on that data. The joining of data and operations
into a unitary building block is "encapsulation." In objectoriented programming, operations that can be performed on
the data are referred to as "methods."
An object can be instructed to perform one of its methods
when it receives a "message." A message is a command or
instruction to the object to execute a certain method. It
consists of a method selection (name) and arguments that are
sent to an object. A message tells the receiving object what
to do.
One advantage of object-oriented programming is the way
in which methods are invoked. When a message is sent to an
object, it is not necessary for the message to instruct the
object how to perform a certain method. It is only necessary
to request that the object execute the method. This greatly
simplifies program development.
Object-oriented programming languages are generally
based on one of two schemes for representing general
concepts and sharing knowledge. One scheme is known as
the "class" scheme. The other scheme is known as the
"prototype" scheme. Both the set-based and prototype-based
object-oriented programming schemes are generally
described in Lieberman, "Using Prototypical Objects to
Implement Shared Behavior in Object-Oriented Systems,"
OOPSLA 86 Proceedings, September 1986, pp. 214-223.
Class Scheme
An object that describes behavior is called a "class."
Objects that acquire a behavior and that have states are
called "instances." Thus, in the objective C language, which
is the computer language in which the preferred embodiment
of the present invention is implemented, a class is a particular type of object. In objective C, any object that is not
a class object is said to be an instance of its class. The classes
form a "hierarchy." Each subclass in the hierarchy may add
to or modify the behavior of the object in question and may
also add additional states. Inheritance is a fundamental
property of the class scheme and allows objects to acquire
20
25
30
35
40
Prototype Scheme
45
50
55
60
65
The prototype scheme is an alternate approach to sharing
knowledge in an object-oriented system. In prototype
scheme systems that use the individual instances, rather than
a class, ("prototypes") are created first, instead of a class.
The prototypes are then generalized by defining aspects of
their concepts that are permitted to vary. The mechanism for
implementing this process is known as "delegation."
Examples of prototype languages include the actor language
and lisp-based object-oriented systems, such as director, t,
and orbit.
Delegation removes the distinction between classes and
instances. To create another object that shares knowledge
with a prototype, an "extension" object is created that has a
list containing its prototypes that may be shared with other
objects and containing personal behavior limited to the
object itself. When an extension object receives a message,
it attempts to respond to the message using the behavior
stored in its personal aspect. If the object's personal characteristics are not suitable to answer the message, the object
forwards the message on to other prototypes to see if one can
respond to the message. This method of forwarding is called
"delegating the message."
An example of delegation is illustrated in FIG. 2. Object
A provides a message 201 to object B. The message includes
a method and arguments to the method. Object B does not
5,481,721
3
4
have the method required by the message. Therefore, object
B cannot respond to the message. Instead, object B sends the
method and message to its delegate. The delegate of object
B is object C. Object C has the method requested in the
message. The method can then be executed and a response
provided to object A.
mentation, a proxy is functionally equivalent to a Unix link,
except that a proxy is not visible to the programmer. It is a
private data structure which is handled by the object manager like other Small-Talk objects.
In the Decouchant reference, three processes cooperate to
perform the object manager functions. These are the network
manager, the main memory manager and the secondary
manager. SmallTalk interpreter processes which access the
objects to perform SmallTalk actions may also be present on
the site. The network manager is the master process of a
SmallTalk site. It ensures consistency of the shared objects
with the other network sites and controls the local processes.
The main memory manager is in charge of the object
management in main memory. It resolves object faults by
allocating free space for the missing object and sending an
object load request to the secondary storage manager. The
secondary memory manager takes care of the object management in secondary storage. This storage is represented by
two files, one of which contains the SmalITalk object table
and the other one contains the object space.
Another prior art method to provide distributed objectoriented programming is described in "The Design and
Implementation of Distributed SmalITalk," John K. Bennett,
OOPSLA, Oct. 4-8, 1987, pp. 318-330. SmalITalk itself is
a language environment that provides a single user with
access to a single object address space. Only rudimentary
support exists within SmallTalk for cooperation among
users, and no support exists within SmallTalk for object
sharing between users or between different machines or
between processes on the same or different machines. The
Bennett references describes "distributed SmallTalk" (DS)
as a method of providing improved communication and
interaction among geographically remote SmallTalk users,
direct access to remote objects, the ability to construct
distributed applications in a SmallTalk environment, and a
degree of object sharing among users.
The system described in the Bennett reference does not
allow remote classes. Instead, the system requires that
classes and instances be co-resident on all processes and
machines. This impacts object mobility adversely. Instances
can only move to hosts with compatible classes and insuring
class compatibility is difficult. In addition, the system of
Bennett does not operate in an object-oriented programming
system that utilizes class inheritance and reactiveness.
(Reactiveness describes the ability of a system to present
objects for inspection or modification).
The system of Bennett uses ProxyObjects and a RemoteObjectTable to implement distributed message passing. A
ProxyObject represents a remote object to all objects in a
local address space. There is one ProxyObject per host per
remote object referenced by that host. ProxyObjects cause a
remote object's message interface to appear to local objects
as if the remote object were locally resident. ProxyObjects
redefine the doesNotUnderstand: message of object. This is
the primary message defined for ProxyObjects. In other
words, messages sent to ProxyObjects are intended to fail.
The system responds to this failure by sending the message
doesNotUnderstand: to the receiver with the message that
was not understood as an argument. The ProxyObject's
response to the doesNotUnderstand: message is to forward
the original message to the RemoteObjectTable on the
appropriate machine or process. The location of the remote
object is part of the internal state of the ProxyObject.
The RemoteObjectTable is responsible for receiving and
replying to messages forwarded by ProxyObjects. There is
one RemoteObjectTable per host. It is the sole instance of
5
Distributed Programming
A disadvantage of current object-oriented programming
systems is that all objects are required to exist in a single
program or process. This prohibits utilizing an objectoriented programming system when writing distributed
applications. In addition, these prior art limitations prevent
the creation of applications that are distributed physically
over networks of machines.
The difficulty of creating distributed object-oriented programs is illustrated in FIGS. 8A and 8B. In FIG. 8A, all
objects are resident in the same program, namely program
LOCAL 801. A sender object 802 sends a message 804 to a
receiver 803. The message may include a method and an
argument. The receiver 803 executes the method of the
message 804 and returns a result 805. The result 805 is
provided back to the sender 802. In the example of FIG. 8A,
the object-oriented program resides entirely on one side of
a boundary 806.
FIG. 8B illustrates a prior art object-oriented programming system attempting to communicate across a boundary
between processes. A local process 801 includes a sender
object 802 that generates a message 804 destined for
receiver object 808. However, object 808 is on the opposite
side of boundary 806. That is a separate process identified as
REMOTE 807. An object, such as receiver 808 which
resides in a different process than a sender object, is known
a "remote object." The language and run time support of the
local process 801 does not provide a mechanism to send a
message 804 directly to the remote object 808. At the
transition point 809 of boundary 806, the message is
stopped.
One prior art approach for writing distributed applications
consists of explicitly defining the boundaries between different programs by specifying protocols, generating client!
server stubs, and communiCating between processes or programs by using function calls that automatically transport
arguments and return values between the client layer and the
server layer. At such boundaries, the object-oriented developer can no longer treat items as objects as soon as the
boundary of the process is crossed. This defeats the purpose
and advantage of using object-oriented programming in the
first place.
Another prior art method for providing distributed object
oriented programming is described in "Design of a Distributed Object Manager for the SmalITalk-80System," D.
Decouchant, OOPSLA 86 Proceedings, September, 1986,
pp. ~52. The Decouchant reference describes the design
of a distributed object manager that allows several SmallTalk-80 systems to share objects over a local area network.
When a local object desires to communicate with a remote
object, the local object communicates with a "proxy" that
locally represents the remote object. A proxy is part of the
private data of the object manager. The proxy has two fields
that describe a remote object, namely, the resident site of the
remote object and a virtual pointer to the object in the
resident site. If the referenced object migrates, the contents
of the referencing object are not modified. The proxy is
updated accordingly by the object manager. In this imple-
10
15
20
25
30
35
40
45
50
55
60
65
5,481,721
5
6
class RemoteObjectTable. The RemoteObjectTable can be
thought of as a set of extensions to the object tables (if
present) of all remote machines. The RemoteObjectTable
keeps track of all local objects that are remotely referenced.
When the RemoteObjectTable receives a message from
some ProxyObject, it schedules a process that will contain
the execution context of the actual message receiver by
sending the message perform to the receiver with the forwarded selector and arguments (if any) as arguments to the
perform message. The value returned by the perform message is returned to the remote sender in a reply message
constructed by the RemoteObjectTable.
Before an object can be sent between processes, the
classes must be checked for compatibility. The three cases to
consider are:
1. The required class is already present and is compatible;
2. The required class is present, but it is determined to be
,incompatible; and
3. The required class is not present.
In case 1, the system proceeds normally. In the second
case, the attempted move fails and the user is notified of the
error. In case 3, the user is asked whether the desired object's
class should be moved. If the response is affirmative, the
object's super class is checked for compatibility. This procedure continues up the class hierarchy until class object is
reached. However, class object may not be moved.
Another method for providing distributed object-oriented
programming is described in ''Transparent Forwarding: First
Steps" Paul L. McCullough, OOPSLA 1987 Proceedings,
Oct. 4-8, 1987, pp. 331-341. As in the Bennett system, the
McCullough system utilizes ProxyObjects and the doesNotUnderstand: message for identifying and transmitting messages. In the McCullough system, the implementation of
doesNotUnderstand: creates an ethernet packet containing
the original message and forwards it to the machine containing the remote object. The proxy contains information in
its instance variables about where the remote object resides.
FIG. 6 illustrates an overview of the operation of the
McCullough system. A message 601 destined for a remote
object is provided to a ProxyObject 602. The ProxyObject
instance forms a representation of the message, including
both the selector and the arguments, suitable for transmission to a remote machine. This message 603 is forwarded
across the process boundary 606 to a remote object 604. The
remote object 604 receives the representation of the message, extracts the message selector and arguments and
executes the message send as though it originated on the
same machine as the remote object. This result object 605 is
transmitted across the process boundary 606 to the ProxyObject 602. The ProxyObject 602 uses the return representation to reconstruct the result object and returns it to the
sender of the original message 601.
The McCullough system implements four possible message parameter passing schemes, namely, pass by value, pass
by reference, pass by proxy and pass by migration. In pass
by value, a representation of the object is shipped to the
remote machine, which in tum reconstructs the object. Pass
by reference cannot be used in a SmallTalk environment
because the compiler prevents assignment to formal parameter variables. In pass by proxy, a proxy for the object and
any messages which are sent to the proxy are automatically
forwarded to the remote object. In pass by migration, we
move an object from one machine to another, leaving a
proxy object in its prior home.
A centralized control scheme, referred to as PolicyMaker,
is used to deliver messages to remote objects. Individual
proxies need not record the current network location of a
shared object, that is the responsibility of the PolicyMaker.
PolicyMaker responsibilities include the decision of whether
to pass objects by value, proxy or by migration, and whether
to forward a message to a remote object or whether to
migrate the object to the local machine for execution. In
addition, PolicyMaker keeps track of open connections
between machines. For each connection to a remote
machine, the PolicyMaker creates an instance of class TransporterRoom. The TransporterRoom takes care of communications protocols between machines, as well as the linearization of messages and objects.
FIG. 7 illustrates the flow control of sending a message
from a machine to a remote object using the scheme of the
McCullough system. A message 701, destined for a remote
object, is provided to a ProxyObject 702. The sender of the
message 701 believes it is sending to a local object, but in
reality it is sending to a remote object. The ProxyObject 702
sends a message 703 to the local PolicyMaker 704. The
PolicyMaker 704 determines whether the arguments of the
message should be sent by copying or by proxy to the remote
object. The PolicyMaker establishes a connection to the
remote machine via transporter room 706. The PolicyMaker
704 provides the message 705 to the TransporterRoom 706.
The TransporterRoom 706 linearizes and transmits the message as message 707 to the remote machine across process
boundary 708.
The TransporterRoom 709 of the remote machine receives
the message 707. The TransporterRoom 709 sends the
reconstructed message 710 to the remote object 711. The
remote object 711 returns a message 714 to the TransporterRoom 709. The PolicyMaker 712 considers the resulting
object and determines whether to return it by value or by
proxy and communicates to the TransporterRoom 709 on
path 713. The TransporterRoom 709 sends the message 707
to the TransporterRoom 706 across process boundary 708.
The TransporterRoom 706 reconstructs the result object and
provides it as message 715 to proxy object 702, which can
then return it to the sending context.
The use of migration limits the performance and ease of
use of these prior art schemes. Migration of objects from
their home process adds to the complexity of the system.
Another disadvantage of these prior art schemes is that each
process and thread must be forked to anticipate each
expected iteration. There is no provision for dynamic recursive communication between processes. In addition, these
prior art schemes rely on a pure, large object oriented
language/environment, such as SmallTalk. This requires
substantial run time support to implement communication
between processes. In addition, the prior art schemes do not
implement suitable object collection methods.
5
10
15
20
25
30
35
40
45
50
SUMMARY OF THE INVENTION
55
60
65
The present invention permits the distribution of objects
and sending of messages between objects that are located in
different processes. Initially, a "proxy" object is created in
the same process as a sender object. This proxy acts as a
local receiver for all objects in the local program. When the
proxy receives a message, the message is encoded and
transmitted between programs as a stream of bytes. In the
remote process, the message is decoded and executed as if
the sender was remote. The result follows the same path,
encoded, transmitted, and then decoded back in the local
process. The result is then provided to the sending object.
BRIEF DESCRIPTION OF THE DRAWINGS
FIG. 1 is a block diagram illustrating the concept of
inheritance in object-oriented programming.
5,481,721
7
8
One port of the video memory 414 is coupled to video
multiplexer and shifter 416, which in turn is coupled to
video amplifier 417. The video amplifier 417 is used to drive
the cathode ray tube (CRT) raster monitor 418. Video
5 multiplexing shifter circuitry 416 and video amplifier 417
are well known in the art and may be implemented by any
suitable means. This circuitry converts pixel data stored in
video memory 414 to a raster signal suitable for use by
monitor 418. Monitor 418 is a type of monitor suitable for
10 displaying graphic images, and in the preferred embodiment
of this invention, has a resolution of approximately 1020x
832. Other resolution monitors may be utilized in this
invention.
The computer system described above is for purposes of
15 example only. The present invention may be implemented in
any type of computer system or programming or processing
DETAILED DESCRIPTION OF THE
environment.
INVENTION
The preferred embodiment of the present invention implements an object-oriented programming system using objecA method and apparatus for distributed execution of
methods is described. In the following description, numer- 20 tive C language. Objective C is an extension to ANSI C that
supports the definition of classes of objects and provides
ous specific details, such as object-oriented programming
syntactic and run-time support for sending messages to
language, operating system, etc., are set forth in detail in
objects. This language model is partially derived from
order to provide a more thorough understanding of the
SmallTalk and has been described in "Object-Oriented Propresent invention. It will be apparent, however, to one
skilled in the art, that the present invention may be practiced 25 gramming; An Evolutionary Approach," Brad J. Cox, Addison-Wesley 1986 and in "SmallTalk-80: The Language and
without these specific details. In other instances, well known
its Implementation," Adele Goldberg, Dave Robson, Addifeatures have not been described in detail so as not to
son-Wesley 1983.
obscure the present invention.
One feature of objective C is "dynamic binding" of
The present invention may be implemented on any conventional or general purpose computer system. An example 30 messages to the actual methods to be invoked, depending on
the class of the receiver. A programmer writing code in
of one embodiment of a computer system for implementing
objective C can create code that sends a message "doSomethis invention is illustrated in FIG. 4. A keyboard 410 and
thing" to an object. The actual method corresponding to the
mouse 411 are coupled to a bi-directional system 419. The
class of the target object does not need to be determined until
keyboard and mouse are for introducing user input to the
computer system and communicating that user input to CPU 35 the message must be sent. This allows objects of any classes
that implementing the doSomething method to be substi413. The computer system of FIG. 4 also includes a video
tuted for the target object at run time without having to
memory 414, main memory 415 and mass storage 412, all
modify the part of the program that sends the message. Also,
coupled to bi-directional system bus 419 along with keyin objective C, programs have run time access to method
board 410, mouse 411 and CPU 413. The mass storage 412
may include both fixed and removable media, such as 40 "signatures," that encode a method's argument and return
types for each class. The method signature provides a way
magnetic, optical or magnetic optical storage systems or any
for two programs to agree on the format of messages.
other available mass storage technology. The mass storage
Moreover, there is a way to extract arguments from the stack
may be shared on a network, or it may be dedicated mass
storage. Bus 419 may contain, for example, 32 address lines 45 using the signature.
for addressing video memory 414 or main memory 415. The
In its preferred embodiment, the present invention is
system bus 419 also includes, for example, a 32-bit data bus
implemented in a computer system using an object-oriented
for transferring data between and among the components,
operating system. One such object-oriented operating system is known as the "Mach" operating system and is
such as CPU 413, main memory 415, video memory 414 and
mass storage 412. Alternatively, multiplex data/address lines 50 implemented on computers manufactured by NeXT, Inc., the
may be used instead of separate data and address lines.
Assignee of the present invention.
The Mach operating system is an object-oriented operatIn the preferred embodiment of this invention, the CPU
413 is a 32-bit microprocessor manufactured by Motorola,
ing system that supports distributed programming. It is a
multi-tasking operating system kernel, allowing multiple,
such as the 68030 or 68040. However, any other suitable
microprocessor or microcomputer may be utilized. The 55 independent "tasks," which provide the basic environment
Motorola microprocessor and its instruction set, bus strucof a program in the form of a demand-paged virtual "address
ture and control lines are described in MC68030 User's
space" and one or more "threads" of execution. Mach
Manual, and MC68040 User's Manual, published by
supports message-passing within and between tasks. This
Motorola Inc. of Phoenix, Ariz.
support is distinct from objective C messaging described
Main memory 415 is comprised of dynamic random 60 earlier.
access memory (DRAM) and in the preferred embodiment
Fundamental to Mach's ability to deliver messages
of this invention, comprises 8 megabytes of memory. More
between different programs is an abstraction called a "port."
or less memory may be used without departing from the
A Mach port is a buffered communication charmel over
scope of this invention. Video memory 414 is a dual-ported
which messages are sent. This charmel, which is maintained
video random access memory, and this invention consists, 65 by the operating system, may be local, may span two tasks
for example, of 256 kbytes of memory. However, more or
on the same machine, or may span tasks on different
less video memory may be provided as well.
machines. The physical location of the receiving end of a
FIG. 2 is a block diagram illustrating delegation in
object-oriented programming.
FIGS. 3A-3C illustrate the distributed processing object
oriented programming system of the present invention.
FIG. 4 is a block diagram illustrating a general purpose
computer system for implementing the present invention.
FIG. 5 is a flow diagram of the forwarding method of the
present invention.
FIG. 6 is a block diagram illustrating the prior art distributed processing object-oriented programming system.
FIG. 7 is a block diagram illustrating another prior art
distributed processing object-oriented programming system.
FIGS. 8A and 8B illustrate non-distributed programming
systems.
5,481,721
9
10
port has no effect on the sender, which always sees a local
reference to the port.
The messages sent on a port are buffered, that is, a sender
writes messages to a port with a "send" primitive, and a
receiver accepts messages with a "receive" primitive. The
messages themselves may be of any size, and consist of a
header followed by zero or more data objects. For efficiency,
large array arguments are passed out-of-line with copy-onwrite semantics. Of particular interest is the ability to pass
Mach ports themselves as data objects in a message. By this
means, one task may pass a port to another, with the kernel
maintaining address translation along the way. This allows
tasks to leam about the existence of new external objects, or
make new "acquaintances," by receiving their ports in a
message. Thus, ports may also be viewed as a reference for
an object that is independent of any particular space, and
may be freely passed between programs.
For a task to communicate with a "receiver" object in
another address space, it must first establish a connection
with that program, and then create a local "proxy" for the
object. When a message is sent to this proxy, the elements
of the objective C message are encoded into a Mach message, which is then forwarded through a Mach port to the
other program. On the receiving side, the message is
received, decoded, and then forwarded it to the target
objective C object. The retum value of the objective C
method is then encoded and sent back to the originator,
where it is decoded and returned as the value. Each part of
this model is now described.
In order to communicate with an object in a different
program or process, that program or process must be known.
The present invention uses Mach ports to represent
"domains" of objects, and a token to identify objects within
that domain. This two-part address is easily communicated,
since the port maintains its identity as it moves between
domains. In Mach, acquiring ports is synonymous with
acquiring privileges to communicate. The present invention
requires that the local domain has send rights to a port that
the remote domain has receive rights to, and also that the
remote domain has send rights to a port that the local domain
has receive rights to, before any communication can take
place. Thus, mutual consent is required to communicate.
In addition to leaming of each other's ports, each domain
must also provide the other with the token corresponding to
its "first proxy." A first proxy is required to bootstrap the
communication. There must be at least one known object in
a remote domain before a message can be sent to it. Because
a connection allows messages in either direction and initiated by either party, each side of a connection must have a
first proxy. This first proxy may be viewed as the "receptionist" for the remote domain, as other objects are obtained
(discovered) by asking this object. This object also is a
candidate for implementing sender authentication.
The present invention provides a means for implementing
an extensible, distributed program in which one task is
responsible for creating other tasks to communicate with.
This is a master/slave relationship; the master can provide
the slave with send rights to the master's port as part of the
creation process. When the slave starts executing, it sends a
Mach message containing send rights to its port and a token
for its first proxy back to the master. The master then replies
with an indication of whether the connection is granted, and
what token to use for the first proxy. This "bootstrap-metaprotocol" results in both tasks knowing about each other,
allowing communication to ensue.
based, message-passing paradigm. The present invention
has a number of advantages over prior art methods of
distributed object-oriented programming. These advantages
include no pre-defined set of messages, transparent to the
programmer, no code generation step and a method for
bridging the gap between object-oriented languages and
object-oriented operating systems.
The present invention differs from the prior art
approaches of Decouchant, Bennett and McCullough. The
present invention uses an object-oriented superset of ANSI
C with minimal run time support to implement transparent
messaging between application programs as opposed to the
prior art systems, that rely on a pure, large, dynamic
object-oriented language/environment, such as SmallTalk.
The present invention either implements a client/server
setup or a master/slave setup that involves forking tasks to
perform background operations and using the present invention to communicate with these tasks. Because communications are serialized by the operating system, remote messages performed by a slave task appear to the program just
like other asynchronous events, such as mouse clicks, allowing the design of a consistent user interface. Modularity,
extensibility and safety are gained by spawning new tasks.
The ability to implement recursive remote mes·saging is an
important feature of the present invention, for example when
user interaction is required to perform the desired task.
The present invention can also be implemented in a
client/server setup. In the client/server setup, both the client
and the server begin independently. Communication is
through an agreed upon method. The client and server can
communicate with each other by looking for a manager for
the communications channel (e.g. network).
The present invention provides a new alternative for
developing extensible programs. Instead of adding functionality by adding code that defines new object classes and then
loading that code into a main program, a new program is
created and forked. If there are any errors in the new
program, they reside outside the main program improving
performance. In addition, processing is parallel and asynchronous, leading to improved performance.
In one embodiment, the first time a message is sent to a
proxy, the receiver is asked for the method signature in order
to allow the proxy's domain to encode the arguments. This
can increase communication time. One alternative embodiment provides for prior agreement between processes so that
two tasks know in advance the method signatures for their
proxies. Alternatively, when prior agreement is not possible
due to the dynamic nature of the required exchange, the
atomicity of the signature request can be changed to communicate all the public signatures for a given proxy, resulting in a single "meta-protocol" transaction for the proxy.
When an object is passed by reference, a new proxy is
typically created. The present invention includes safeguards
to guarantee that if a remote object is encoded twice, the
same proxy (in the pointer equality sense) will be obtained
in the local domain. This unicity of proxies is maintained by
a table which maps tokens of remote objects to their local
proxies and looks for previously created proxies when an
object pass by reference is decoded. The present invention
keeps all proxies until the communication with the remote
domain ends. At that time, the table is used to de-allocate all
proxies.
The operation of the present invention is illustrated in
FIGS. 3A-3C. Referring first to FIG. 3 A, a local process
901 is separated from a remote process 902 by boundary
906. The boundary 906 could be a separation between
5
10
15
20
25
30
35
40
45
50
55
60
Distributed Object Oriented Programming
65
The present invention provides a method for different
processes to communicate, using a traditional language-
5,481,721
11
12
programs on the same computer or it could represent the
separation of two different machines on a network. The local
process 901 includes a sender object 905 that sends a
message to receiver object 909. The object 909 is located in
the remote process 902. However, the sender object 905 can
send its message 903 to the remote object as if it were a local
object.
The local process 901 includes a receiver proxy 904 that
accepts the message 903. The receiver proxy 904 is an object
that executes a forward:: method. The receiver proxy 904
encodes the message and transmits it across the process
boundary to the remote object. In the preferred embodiment
of the present invention, the proxy 904 encodes the message,
(which is a language based message such as, for example, an
objective C message), as an operating system message, such
as a Mach message 907, and transmits it to the receiver
object 909 in the remote process 902. The receiver object
909 decodes the Mach message into a language based
message for execution or handling in the remote process
902.
The present invention supports nested, recursive, remote
messages. That is, when a message is sent to a remote object,
that remote object may send other messages back to the local
process (which may again send other remote messages), as
part of its calculations before providing a reply to the initial
message. These messages may be nested arbitrarily deep. If
only the sender itself is sent as an argument, (such as
illustrated in FIG. 3 A), the receiver determines what further
information is required from the sender and sends messages
back to the local process to obtain that information before
generating a reply.
Referring to FIG. 3 B, the receiver object 909 requires
additional information from the sender object so it generates
a request message to the sender object 904. However, since
the sender object 904 is not resident in the remote process
902, a sender proxy 910 is created in the remote process 902.
The sender proxy 910 encodes the request into a Mach
message and transmits it across process boundary 906 to
sender object 905. The Mach message is decoded into a
language based message and generates a response. This
response is sent back to the receiver object 909, (again via
receiver proxy 904).
Referring to FIG. 3 C, the receiver object 909 then
performs an execute 911 on the original message to generate
a result object 912. The result object 912 is encoded 913 and
transmitted across process boundary 906 to result proxy 914
in local process 901.
In the present invention, proxies are not required to be
created in advance. Once one proxy of a remote process
exists, N proxies can be created for communication with that
process. The present invention also permits the sending of
objects themselves across process boundaries.
The recursive nature of the present invention is useful
when the remote object does not recognize a method sent to
it by a local object. For example, the local object may send
a message to a remote object requesting it to execute the
method "foo". If the remote object does not recognize the
method, it can ask the sending object "what is foo?" All
objects recognize the method "what is". The sender object
can then respond with instructions concerning the nature of
the method being investigated. For example, the sender can
reply that foo is a method that requires an integer. If no
integer has been provided, the remote object can then
request the integer.
The creation of the first proxy is provided automatically
in the present invention. The first time a process is accessed,
it must call a process referred to as the "proxy receptionist".
By definition, the first call to a new process is to be at
sequence number O. The first proxy by definition has a
sequence number of O. Subsequent proxies, as needed, are
defined and the sequence numbers are provided to the other
process.
In the preferred embodiment of the present invention,
communication between processes is implemented in a
master/slave or client/server relationship. In the case of a
client/server relationship, the server may "publish" its port
in an appropriate place on the system. The client looks up
this port and then uses it to initiate the bootstrap-metaprotocol described above.
The establishment of a connection defines only the first
proxy on each side. Proxies for any other objects that need
to be communicated are created dynamically as they are
encountered. For example, if a remote method returns a new
object, a new proxy is created when decoding the result
locally, such that the local program could send a message to
this new remote object without any explicit setup.
Once a connection is established, a message may be sent
(in either direction). To send a message, the arguments must
be encoded into a form that is representable in a Mach
message, so that the receiver may decode them correctly. To
do this, the sender must know the method signature of the
message. The method signature is part of the "protocol" that
both sender and receiver must understand in order to communicate, and is a domain-independent encapsulation of the
method name, its argument types, and its return value type.
Although a protocol may be arranged by prior agreement
in many cases, the present invention determines the protocol
dynamically by asking the receiver how to encode the
arguments for each message as it is encountered. During the
first attempt to send a given message to a remote object, the
local domain consults the remote domain to get the signature
corresponding to the actual class implementation that will
ultimately receive the message. This method signature is
cached on a per-connection basis, with the assumption that
the class of a remote object will not change for the duration
of the connection. Thus, subsequent messages use the
cached signature, and do not have the overhead of this
"meta-protocol" transaction. This dynamic aspect is useful
for type checking, and allows one program to "learn" how
to talk to another program.
The argument encoding for standard C data types is
explicit and strictly pass-by-value, and maps substantially
directly onto a Mach message. Pointers to C data structures
are not encoded. Arguments that are first-class objects (as
opposed to simple C data types) are handled specially; they
are asked to encode themselves. The default encoding
scheme that most objects inherit is to allocate a token (if one
does not already exist) in the local domain, and encode only
that token. Along with the port of the local domain, this
constitutes an object reference (via proxy), and when it is
decoded on the receiving side, results in a new proxy for that
remote object.
Thus, first-class objects by default get passed by reference
instead of by value. For example, when domain A sends a
message with object X as an argument to a remote object in
domain B, a new proxy is created in domain B to represent
X. Any subsequent message that domain B sends to X results
in another remote object transaction. In the present invention, an implementation of an object class is free to choose
to implement a different encoding scheme, for example one
that encodes the object by value, though this requires that
both sender and receiver implement that class of object. The
5
10
15
20
25
30
35
40
45
50
55
60
65
5,481,721
14
13
"pass-by-proxy" scheme does not have this restriction and is
generally preferred.
Because objective C implements functional messages, a
return value is always returned in a reply message. It is
encoded exactly the same way as arguments are. In particular, if the result is an object or a proxy, it is encoded as a
proxy or an object, respectively, in the other domain. The
reply message also encodes information about errors or
exceptions that may have occurred, so that they can be raised
in the local context. That is, an error occurring while
executing a message sent to a remote object is caught and
returned to the caller, so that the exception is raised in the
local domain. This makes error handling transparent.
Remote exceptions may be handled the same way as local
exceptions.
The use of a single port to represent a domain of objects
allows an efficient and simple implementation. A one-way
message is used when forwarding a message to a remote
domain. Messages are received on the local domain's single
published port while waiting for the reply. Since all messages (including both the reply message and any other
messages initiated from remote domains) arrive on the same
port, each one can be handled serially. There is no global
state to keep track of (the logic is implemented in a reentrant manner), and each message and reply have matching
sequence numbers, so it can be determined when the correct
reply has been received.
In effect, the low level routine to actually forward the
message to the remote domain becomes the main loop of the
program until the reply is received. There may be many
nested levels of this low level routine at one time. Outside
the scope of a locally-initiated remote message (i.e., the
"idle" state of waiting asynchronous messages to arrive), the
local domain's port is listened to by the main program, along
with other non-remote-object related events. This approach
contrasts with that of the prior art McCullough system,
where a process or thread is forked to field every expected
reply. The present invention achieves an order of magnitude
in performance by avoiding the forking when communicating.
An example of a computer program listing that may be
used to implement the present invention is described in
Appendix A. This computer program listing is given by way
of example only. The present invention may be practiced
using other programs and methods as well.
5
10
15
20
25
30
35
40
45
Automatic Forwarding of Messages
The present invention, in its preferred embodiment, takes
advantage of a method referred to as "automatic forwarding
of messages." This method is the subject of copending
patent application Ser. No. 07/695,316 filed May 3, 1991,
entitled "METHOD FOR PROVIDING AUTOMATIC
FORWARDING OF MESSAGES AND METHODS" and
assigned to the assignee of the present invention. This
method is described below.
In objective C, when an object receives a message that
contains a method that the object does not recognize, an
exception is provoked leading to an error. The present
invention, instead of provoking an exception, redirects the
message to an acquaintance that can understand the message. For example, if an object receives a message containing a method that the receiving object does not contain, the
message is forwarded to an acquaintance object that does
contain the method. This provides the advantage of inheriting the method from the acquaintance object but does not
50
55
60
65
require the first receiving object to actually have the method
itself. This reduces code size the memory requirements.
The present invention has a plurality of uses. For
example, a new object class can be defined so that one of its
instances (attributed object) adds an attribute to another
object (its forwardee). In that situation, automatic forwarding occurs when an attributed object receives a message that
is irrelevant to the attribute, and the method is forwarded to
the forwardee. In another situation, some functionality is
applied before and/or after the forwarding. This can be used
in the case of a locking data structure where all methods
must be redirected to the locked data after acquiring the
lock, and where the lock must be released after the execution
of the forwarded method. The present invention also has use
in the case of forwarding messages in a distributed environment where there is no explicit forwardee. Rather, there
is a network address of the forwardee.
The implementation of the present invention in the preferred embodiment requires trapping the "message not recognized" exception of objective C, retrieving all of the
arguments of the unrecognized message, and sending the
"forward::" message to the object.
The resulting automatic forwarding system of the present
invention is more powerful than multiple inheritance and is
transparent to the programmer and developer. The system is
general, because the forwardee is not explicit, thus permitting solutions to a large class of problems.
The present invention uses the forward:: command so that
subclasses can forward messages to other objects. The
format is forward: (SEL) aSelector:(marg_list) argFrame.
When an object is sent an aSelector message, and the run
time system cannot find an implementation of the method
for the receiving object, the run time system sends the object
a forward:: message to give it an opportunity to delegate the
message to another object. If the forwardee object cannot
respond to the message either, it also has the opportunity to
forward the message. A forward:: message is generated only
if a selector method is not implemented by the receiving
object's class or by any of the classes it inherits from.
The forward:: message thus allows an object to establish
relationships with other objects that will, for certain messages, act on its behalf. The forwarding object is, in a sense,
able to "inherit" some of the characteristics of the object it
forwards the message to. The forwarding object is not
limited to the forwardees it may select, and a forwardee
relationships may be formed with more than one object at
the same hierarchical level. Therefore, the present invention
provides the advantages of multiple inheritance without the
code size problem.
In addition to forwarding messages, the forward:: method
can locate code that responds to a variety of different
messages, thus avoiding the necessity of having to write a
separate method for each selector.
If implemented to forward messages, a forward:: method
has two tasks. First, to locate an object that can respond to
the aSelector message (this need not be the same object for
all messages). Second, to send the message to that object
using the performv:: and performv method.
The operation of the present invention is illustrated in the
flow diagrams of FIG. S. At step SOl, Object A sends an
aSelector message to object B. At decision block 502, the
argument "Implementation exists in Object B?" is made. If
the argument is true, the method of the aselector message
can be executed by object B. If that is the case, the system
proceeds to step 503 and the method is executed. If the
argument is not true, the system proceeds to step 504 and
invokes the forward:: method.
5,481,721
15
16
The forward:: method then performs the first of its two
tasks at step 505. Namely, it attempts to locate an object to
respond to the aselector message. At decision block 506, the
argument "Object found?" is made. If the argument is true,
then forward:: has successfully found an object to respond to
the aSelector message. In the present invention, the forwarding object is typically a proxy object.
The objective C run time code routines for implementing
automatic forwarding of messages is as follows:
5
II provide a default error handler for unrecognized messages
static id-forward (id self, SEL sel, ...)
{
The system then proceeds to step 507, the message is
encoded and transmitted as an operating system message to 10
another process. At step 508, the operating system message
is decoded and provided to the destination object. At step
509, the destination object executes the method of the
message to generate a result. At step 510, the result is 15
encoded and transmitted to the first process as an operating
system message. At step 511, the message is decoded and the
result is provided to the sending object.
If the argument at decision block 506 is not true, the
system proceeds to decision block 512. At decision block
512, the argument "forward again?" is made. If the argument
is true, the message is forwarded again and a search for an
object to respond to the message is made. If the argument is
false, the system proceeds to step 513 and an exception
(error) is invoked.
In the case in which an object forwards messages to just
one destination, a forward:: method could appear as follows:
id
relVal;
II the following test is not necessary for Objects (instances of
Object)
II because forward:: is recognized.
if (sel =@selector (forward::)) }
_objc_error (self, _errDoesntRecognize, SELNAME
(sel));
return nil;
}
retval =[self forward: sel : &self];
return retval;
{
Method smt =(Method) objc_malloc (sizeof (struct
objc_method));
smt->method_name sel;
smt->method_types = "";
smt->method_imp = (IMPLforward;
_cache_fill (savCls, smt);
20
Method smt = (Method) objc_malloc (sizeof (struct
objc_method));
smt->method_name = sel;
smt->method_types = "";
smt->method_imp = (IMP)_forward;
cache_fill (savCls, smt);
25
}
30
II the class does not respond to forward: (or, did not supply a
dest)
,
{
- forward: (SEL)aSelector
:(mar~list)argFrarne
{
if ([friend respondsTo:aSelector])
return [friend performv:aSelector:argFrarne}:
return [self doesNotRecognize:aSelector];
35
Method smt = (Method) objc_malloc (sizeof (struct
objc_method));
smt->method_narne = sel;
smt->method_types = '''';
smt->method_imp = (lMP)_forward;
_cache_fill (savCls, smt);
}
return (IMPLforward;
ArgFrame is a pointer to the arguments included in the
original aSelector message. It is passed directly to performv:: without change. The default version of forward::
implemented in the object class invokes the does not recognize: method. It does not forward messages. Thus, if a
user chooses not to implement forward:: methods, unrecognized messages will be handled in the usual way.
40
Thus, a method and apparatus for providing distributed
processes is described.
5,481,721
17
18
APPENDIX A
ffimport
ffimport
fiimport
ffimport
Jlimport
1* Declarations that will go away *1
extern BEL _sel_registerName(STR key);
/*****~***********
Definitions
extern int defaultCornmTimeout; 1* in millisecs, <0 means infinite *1
extern int remoteHessageReceiveCount; 1* increments when a msg is received *1
1*
The following type of function may be passed to the beginListeningOn:rootObject: m
ethod. It gets asynchronously called during remote message sending. For example, an app co
\lId register the port and function with DPSl\ddPort when the boolean is YES (and DPSRemoveP
ort when NO). *1
typedef void (*remote_message_handler_t) (msg_header_t *msg, void *userData);
typedef void l*receive_enable-proc_tl (port_t port, remote_message_handler_t fun, BOOL shou
IdEnable) ;
typedef enum (
ffdefine REHOTE_EXCEPTImLBASE 36000 1* less than appkit base *1
I' Format of exceptions is a label and a message string
*1
GENERIC_REMOTE_EXCEPTION = REMOTE_EXCEP'1'l0lCBl\SE,
'I'H1rmU'CREMOTE_EXCEPTION,
Ll\ST_REMOTE_EXCEPTION
RemoteException;
/*****************
communication
@interface communication: Object (
@publlc
port_t
sendPort;
int
timeout;
1* in milliseconds *1
NXllashTable *objectsGivenAway;
NXHash'l'able *allProxies;
+ beginListeningOn:(port_t)listenPort enableProc:(receive_enable_proc_tlaProc;
f* Initialize the remote object system.
.
ellableProc is called immediately with a boolean of YES. ' f
+ new: (port_t) port timeout: (int) aTimeout;
+ findCollunForPort: (port_tl aPort;
@end
Remote Objects
**************************/
@interEace RemoteObject: Object (
communication
*comm; 1* nil· means "local" *1
unsigned
name;
1* object name; 0 means localRoot *1
HaslJ'I'able
*knownSelectors;
I * cache * I
.. messageReceived:(msg_header_t *lmsg/
5,481,721
19
20
+ lIewHemoLe: (unsigned) remoteName withcomllluIlLcation: (CollununicaLiol1
/* This is used only for bootstrap */
*'
communication;
+ l-egistel"LocalHoot :root;
/* Hegister the local root, and return a remote object with name 0;
Call only be called once */
+ new Local: local withCollununLcation: (Collullunlcatfon *' conUllunication;
/* search for a local-HemoteObject that corresponds to local id.
If nOlle found, creates one */
-
(l1l1siglled)remoLeObjecLName;
-
(unsiglled) methodl\rgSize: (SEL) sell
/* size of the arguments of the remote object, including self and sell
o iff error * /
- forward: (SEL) sel : (void *) args;
@end
Encoding Protocol
@interfilce Object Wbject_MakeHemote)
- encodeHelllotelyFor: (CollUlIunication *) cOJlulIunicatiOi! freeAfterEncoding: (BOOL *) flag;
/* This method is called for each object being encoded; By default, it consists in cre
atillY a new "local" remote object (Le. passing the object by reference). To pass the obj
ect 1.>," vilJl1e, just return the object. '1'0 substitute another object, just return it.
Ifr (lag is set, the returned object will be [reed after encoding. */
- after'l'orLHeading: (Communication *) communication;
/* This method is called after decoding an object to give an opportunity to replace it
odyillal object can be freed */
- instanLiateObject: (const char *)className:
- setOutleL: (const char *)outleLName with:dest;
@end
5,481,721
21
22
"import .. Hellloteobj eet .11'
Uimport 'NXPortStream.!J'
II import
"invort
ffimport
"import
1IilOport
"import
Uimport.·
ffilllport
Jlimport
Uimport
"imporl
Forward Definitions
static void hanclleRemoteMessage (msg_header_t *111, void *userData);
static void relilote/\sk (port_t port, lIIsg_header_t *II1Sg, int timeout);
lif 0 II Never tried
static void remote'l'ell(port_t target, msg_header_t *msg, port_t sender, int timeout);
ffelld.if
Utilities
int de[aultColI\ln'l'imeout
15000;
BaaL enableWarniug ~ NO;
static void logv(const char *format, va_list args)
prilltf(UnemoteObjects[pid %dJ :\t", getpid();
vpr.tlltf (founat, args);
static void ROLog (const char *format, ... )
va_list
args;
va_sLarL(args, format);
logv(format, args);
va_end(args) ;
static void wal-ning(const char * format, •.. )
va list
args;
va_start (args, format);
if (enableWarning) logv(format, args);
va_end(args):
static void error(const char *format, ... )
va_list
args;
va_start (args, format);
logv([ormat, args);
va_end (args) ;
NX_RAISE(GENERIC_REMOTE_EXCEPTION. "Internal error", NULL);
static int generateSequellceNumber()
static int nUlIlber=O;
llumber+·' ;
if (!number) number ~ 1:
/* useless */
5,481,721
23
24
returII lIumber-;
@inLer[ace Object (Private_Imports)
- reallyFree;
@end
Selector Info
@inter[ace RemoteHethodlnfo: Object {
NXlltom
typedesc;
static RemoteMethodlnfo *knownRemoteMethodln[o
nil,
+ 10calHethodlnfoFor:IClasslclass : (SEL)sel,
/" Return RemoteMethodlnfo for a local method;
Can return lIil */
- encodel1ethodParams:(void *)args onto: (NXPortStream "I stream:
/* encode the method frame onto stream (excluding self and sell */
- (void • ) decodeMethodPat-amSI'rom: (NXPortSlream *) stream,
/* decode the method frame from stream;
return a freshly malloced pointer, never NULL (unless errorl */
- eJH:odef.lethodHet :result onto: (NXPortStream "I stream,
/' encode the method return value */
- decodeMelhodHetFrom: (NXPortStream *lstream,
/* decode the return value, */
- (unsignedlsizeOfl'arams;
/* Return the size of all parameters including self and sel *f
@end
@implelllentation HellloteMethodlnfo
static unsigned hashMethodlnfo(const void *info, canst void *data)
consL Hemotel1ethodlnfo
*rm
data;
return (unsignedlrm->typedesc;
/* depends on the fact its uniqeud *f
J
static int isEqualMethodlnfo(const void *info, const void *datal, canst void 'data21
const HemoteHethodlnfo
*rml = datal;
const HellloteMethodlnfo
*rm2 = data2;
return (nlll->typedesc == rm2->typedescl;
static NXllashTablePrototype proto
static NXllash'!'able *alll1ethodlnfos
{hashMethodlnfo, isEqualHethodlnfo. NXNoEffectFree, OJ
NULL;
+ initialize {
if (! knownRemotel1ethodlnfo) {
iJllMethodlnfos = NXCreatellash'rable (proto, 0, NULL);
knownHellloteHethoulnfo = IRemoteMethodlnfo localMethoulnfoFor: (Class) [Object clas
s1 :Rselector(remoteMethodInfo:JJ;
)
return self;
+ locaHlethodlnfoFor: (Class) class : (SELl sel (
method = class_getInstanceMetliod(class, sell 1
11ethou
HemoteMethodlnfo
*previous;
5,481,721
25
if
26
method) {
error ("."" locaI11ethodlnfoFor:: for '%s' with '%s' return nil \n", [(id) class name
J, sel_geLNall1e (sel)) ;
return nil;
(!
)
self = [super new];
typedesc = NXUniqueString(method->method_types),
previous = NXlIashGet(allHethodlnfos, self);
if (previous) {[self freel; return previous;
NXllashlnsert (alll1ethodln[os, self);
return self;
- encodenemotelyFor: IConununication .) conununication freel\fterEncoding: IBOOL .) flag (
return self;
- wri tePortstream: (NXPortStream") stream (
[super writePortStream: streron]:
warning("writing a Method:%s\n", typeuesc);
NXWritePortTypes!stream, "%", &typedesc);
return self;
- readPortStream: (NXPortStream") stream {
[super readPortStream: stream];
NXReadport'l'ypes (stream, "%", &typedesc);
warning("reading a Method:%s\n", typeuesc);
return self;
- encodeHethodParams: (void .) args onto: (NXPortStream .. ) stream {
struct objc_method met;
uns iyned
lib:
unsigned
index = 2; /.. skip result, self and sel • /
int
offsetO;
char
·type;
lIlet . method_types = (char .) typedesc;
nb = method_getNumberOfll.rguments(&met);
NXWri tePort'l'ypes (stream, "i", &nb); /. just for redundancy */
lIlethod_getl\l-gumenLlnfo(&met, 0, &type, &offsetO);
While (index < nb) {
char
"type;
int
offset = 0;
void
*arg;
methoo_getl\rgumentInfo(&met, index, &type, &offset);
if (I offset) error!"·· .. encodeMethodParams:onto: cannot extract %d argument for t
ype desc %s\n", index, typedesc);
arg ~ {(char ·)args)+offset-offsetO;
warning ("encodeMethodParams:onto: type~%s value~Ox%x\n", type, • (void "·)arg);
NXWritePort'l'ypelnternal(stream, type, arg);
index++;
)
return self;
- (void .) decodeMethodParamsFrom: (NXPortStreron *) streron {
struct objc-wethod met;
unsigned
nb;
unsigned
index = 2;
unsigned
count;
void
~args;
int
offsetO;
char
·type;
5,481,721
27
28
= (cha.c .. ) typedet;c:
nb = method_getNulllberOfArguments(&meL);
NXHeadPort'l)'pes (stream, .. i", &count);
if (count ! = nl;) (
error("decodeHethodParamsFrol11: incompatible method params");
return NULL;
Im.~L .lI1r::!l.hod_lypC!;
)
Ve
,nethod_getl\rgumentlnfo(&met, 0, &type, &offsetOl;
args = calloc «(self sizeOfParamsl, 1);
while (index < nb) (
char
*type;
int
offset = 0;
void
*arg;
method_getl\rgumentlnfo(&met, index, &type, &o[[set);
if (! offset) error("*** decodeHethodParamsFrolll: cannot extract %d argument for ty
deBe ~s\Il", index, typedesc);
arg = «char *)args)+of[set-o[[setO;
tlXReadport'l)'peInternal (stream, type, arg);
warning("decodeHethodParamsFrom: type=%s value=Ox%x\n", type, * (yoid **Iarg);
index++;
1
return args;
- encodeHethodHet:result onto: (NXPortStream *)strearn {
II?? -> SN: way to get return types?
i[ (typedesc(OI == 'v') return self;
if (typedesc(OI == 'c') (
//?7 BOGUS, of course
NXWritePortTypelnternal(stream, "i", &result);
else (
NXwritePort'l'ypelnternal (stream, typedesc, &resul t) ;
1
retuln self;
- decodeHethodRetFrom, (NXPortStream *)strealll (
id
result = nil;/* important init. [or result less than 4 bytes */
//?7 -> SN: what iff result more than 4 bytes?
if (Lypedesc[OJ
'v') return nilJ
if (typedesc[Ol == 'c'l (
II?? BOGUS, of course
NXReadPort'lypelnternal(strearn, "i", &result);
else (
NXReadPort'l)'pelnternal (stream, typedesc, &result);
)
teLunl result;
- (unsigned)sizeOfParams {
struct objc_lIlethod met;
met.method_types = (char *)typedescl
return method_getSizeOfArguments(&met);
Ilend
@interface Object (Object_RemoteHethodlnfo)
- remoteMethodlnfo:(SEL)sel;
@end
Ilimplemelltation Object (Object_RemoteMethodln[o)
- remoteI1ethodln[o: (SEL) sel (
5,481,721
29
30
LcLulll [He1l1oteHct!loc!ln[u localMellwc!ln[ol'or: (Cluss) [self class] :sel];
@encl
communication
@implemelltaLion COllUnunication
typec!ef struct _LocalToRemote {
id
local;
Remoteobject
·remote;
Local'l'oHemote;
/. remote-;>name
(unsigned)local ./
static void freeLocalToHemote(const void 'info, void *data)
Local'l'oHemote
'ltr = data;
IILr->remote reallyFree);
free(data);
static NXllashTablePrototype proxyProto:
static id cOllUTIList.
=
nil;
static receive_enable_proc_t enableProc
static port_t replyPort = PORT_NULL;
NULL;
.. beyinl.isteningull: (port_t) listenPort. eJlableProc: (receive_eJlable_proc_t) aProc
.•:eplyPot"t = listenPort;
pOlt_set_backlog (task_self () ,listenPort,PORT_BACKLOG_HAX);
ennbleProc :::: aProc;
i [ (EnableProc)
reLurn self;
~
('enableProc) (replyPort, handleRemoteHessage, YES) ;
new: (port_t) port timeout: (int) aTimeout (
NXflu"IJ'l'iJulePrototype
proto! = NXPtrStrucLKeyProtoly.pe1
protol. free = [reel,ocalToHemote;
if (! cOllunList) cOllJmList = [List. new);
self = [super newl;
semlPort = port;
timeout = a'rimeout;
objecLsGivenAway = NXCreateHashTable(protol, 0, NULL);
aUl'roxies = NxcreateHashTable(proxyproto, 0, NULL);
[COlllln),!"t iJ{kl0lJject:self);
retuln self;
+ filldColluuForPort: (port_t) aPort {
illt index = [collUnList count] 1
whil e (index- -)
if «( (Communication .) [corrunList objectAt: index) ->sendPort
return [comrnList objectAt:index);
returll nil;
aPort)
- fL-ee (
[commList removeobject:self];
NXFreellashTable(objectsGivenAway);
r·/XFreellashTable (all Proxies) I
return Isuper freel1
- beforeEncoding:object onto: (NXPortStream *)stream freeAfterEncoding:(BOOL *)flag (
5,481,721
31
32
Lel.lIlll !ooject ellcodeHeIlI(J:;elyFor: strea,"->conllnunicatioll fleel\[terEncoding:flag];
- afterVecoding:object from: (NXPortStream *)stream {
reLurn (object a fterPortReading: stream->collununication);
@end
static id 10calRoot
nil;
static id 10calRemoteForRoot
nil;
@implementatioll RemoteObject
+ initialize {
/* We have to initialize knownRemoteMethodlnfol */
[llemoteMethodlnfo initialize];
retul-n self;
+ newHemote: (unsignedl remoteName withColtununication: (Collununication *) COllUlIUnication (
self
[super new);
CQII1II1 ~ cOllununicatioll;
lIame ~ remoteName;
if (NXllashlnsert (communication->allProxies. self)) error ( • newRemote·: already in table!
") i
return self;
+ newLocal: local withColMlunication: (CofiUllunication *) cOllununication {
],OGi] l')'oHell1ote
pseudo;
LOGi] 1']'oHemote
*1 tr;
if (J local) return nil;
if (loGal ~~ 10GalRoot) return 10calHemoteForHoot;
pseudo. local ~ local;
11: r ~ NXllashGet (conununication->obj ectsGi venAway. &pseudo);
if (llr) return Itr->remote;
Itr = malloc (sizeof (LocalToRemote») ;
Itr->local = local;
Itr->remote = [self new];
Itr->remote->name = (unsignedllocal;
NXllashlnsert (communication->obj ectsGi venllway. 1 trl ;
return Itr->remote;
+ registerLocalHoot:root {
if (localHootl error("registerLocalRoot: root registered twicel");
local Root = root;
,etu,Tl (localHemoteForHoot = [self new) J;
+ messageHeceived:(msg_header_t *)rnsg
halldleHemoteMessage(rnsg, NULL);
return self;
- reallyFree (
[knownSelecto,s f,ee);
,eturn [super free);
- free {
5,481,721
33
!.;yH Il.'q
l.elUlli
(IK>c:_";HH,
"Hr~lll(JlC'
34
0bjf~Ct
Ox1;x
1.
cere' i vt:d
i1 r.:'(~"
f
se.ll);
nili
staUe ullsiglled hashProxy(const voiu *in[o, const void *uata)
retU1:11 «(Remoteabject *) data) ->name;
static illt iSEqualProxy(coIlst void *info, const void *datal, const void *uata2)
return «(HemoteObject *) datal) ->name ;; «ReIHoteObject *) data2J ->name;
static void freeProxy(const void *info. const voiu *daLa) (
[(iu)data reallyFreeJ;
static NXllasl1TablePrototype proxyProto ; (hashproxy, iSEqualProxy, freeProxy, 0)1
- (ullsiyned)rellloteObjectName ( return naIHe; )
- remoteHethodlnfo: (SEL) sel
id
res;
id
arg8[4J;
if (sel ;; I!!selector(remoteHethocllnfo:» return knownRemotel1ethodlnfo; /* to avoid inf
inite recursion */
res; lY..llowll[;electors valueForl SN 1I0w to fill args cleanly
bzero(args, 8izeof(id)*4);
(
Bethou method; class_getIl1stanceHethod{ (Class) [Object class).
thodlnfo:)) ;
cllilr
*type;
lnt
offset2;
int
offsetOI
SEL
*ref;
method_getllrgumentlnfo(method. 0, &type, &offsetOl;
meLhod_getllrgumentln[o(method. 2, &type, &0££8et2);
lef; (SEI, 'I «(c1w.r *largs)+offset2-offsetO);
'ref ; sell
@selector(rernote~le
res; [(iu) self forwaru:@selector{remoteMetl1odln£o.) :arys);
if (i knownSelectors) knownSelectors ; {lIash'I'able llewKeyOesc'":")1
I kuowIlS{?lectors insertKey: (void *) sel value: resJ ;
relunl res;
- ellcodeHemotelyFor: (COllullUllicat1on *) cOlluRunication freeAfterEncoding:
return selfJ
- writePortStream. (NXPorlStream *) stream
[super writePortStream: stream] I
NXWr itePort'Iypes (stream, '11", &comm. &name);
return self:
- readPortStream: (NXPortStream *) stream
[super readPortSLrearn: stream];
NXHeadPorL'I'ypes (stream, "ii·. &COll1lll, &na111e) I
reLurn sel [:
- after"Por"tReading: {Collununication
* 1communication {
(BaaL *1
flag (
5,481,721
35
i l
(!
c;<.111l111)
36
(
id
previous;
/* it was local for the other guy */
warning("in afterPortHeading - read Hemote %d\n", name);
conlin =
communication;
previous = NXlIashGet (conununicatioll->allProxies, self);
i f (previous) (
warllillg("receiving same name=Ox%x previous=Ux%x self=Ox%x\n", name, previous,
seH) ;
[self reallyFreeJ;
return previous;
)
NXlIashInsert(conununication->alIProxies, self);
return self;
else (
1,0cal'l'oHemote
pseudo;
LocalToHemote
'ltr;
pseudo. local = cid)name;
i f (! name) (
if (! localRoot) error("invariant broken in afterPortReading,");
[self reallyFreel;
return localRoot;
)
ltr = NXllashGet (collununication->objectsGivenAway, &pseudo);
if (! Itr) errorC"afterportReading:");
if (ulwigneu)ltr->local !=name) (
error("afterPortHeading: broken illvariant");
)
warlling("in afterPortReading - converting Remote %d illto local Ox%x\n" , name, ltr>loca.l) ;
[self reaJ.J.yFreel;
return ltr->local;
- (unsigned) methodJ\rgSize: (SEL) sel {
Hemotel1ethodInfo
'selInfo = (self remoteMethodlnfo:sel];
if (! se]1nfo) returll 0;
return !sellll[o sizeOfParamsl;
- forward:(SEL)sel : (void ')args {
char
buffer(MSG_SIZE_I~AX];
msg__header_t
*msg = (msg_header_t *) buf fer:
NXlItom
selNam8 = NXUniqueStrillg (sel_getName (sell);
int
sequence = generatesequenceNumber();
NXPorLSLream
'stream = NXOpenEncodePortStream(msg, sequence, cOllun);
HcmoLeHethoulnfo
*sel1nto = [self rellioLeMethodlnfo:selJ;
id
result;
inL
errorCode;
if (! selInfo) error (" forward:, cannot find remote s.elector %s". selName);
warning ("entered forward:, self=%d selName=%s\n". name, seIName);
NXWriLePortTypes(stream, "@%", &se1f, &seIName);
1ge1111fo ellcoueHeLhouParamG;args onto:strealll];
NXcloseElIcodePortSLrealll(stream);
warning (" in forward:: - %d made packet for [Ox%x comm: %x %s ... ] \n", name, COJlun, self,
selName);
,
rell1otel\sk(cOIIUll->sendPort, msg, comm->tillleout);
/. let's decode the resul t */
warning (" in forward" seIName=%s received answer\n". seIName):
5,481,721
38
37
stream = NXOpeuDecotlePortStream{msg ,
COllUn);
NXReadPort'l'ypes (stream, "i", &errorCode);
if (errorCode) error("fon~ard:: Error occurred during remote execution");
l-esult = [sellnfo decodeHethoclRetFrom:stream];
NXCloseDecodePortStream(stream) ;
warning("in forward:: - %d result decoded fOl- (Ox%x conull:%x %s ... ]\n", name, cclnun, se
1[, selNiJllIe);
return result;
@end
Object Mise
@interface Object lObject_MakeRemotel
- setllction: (SEL) theSelector;
@end
@implementation object (Object_NakeRemote_Importl
- encodeRerl1otelyFor: ICommuniCiltion *) communication freellfterEncoding: (BOOL *) flag (
\"arning (" in encodeRemotelyFor - converting local Ox%x (%s) into remote\n", sel f,
name}} ;
retuul [RemoteObj ec t newLocal: self wi thConununication: conununicaLion] ;
- aftel-PortReading: (Conununication *) cOlmllUllicatioll {
return self;
- instilntiateObject: (const char *)className {
return [objc_getclass ({char *) className) new];
- seLOuLlet: (const char ')outletName with:dest (
chilr
methodString [256] ;
sel;
SEL
strcpy(methoclString, 'set");
strcat(methodString, outletName);
strcat (methodString, ' : ' 1 ;
if (methoclString (3] >= 'a' && methodString [3] <= 'z')
methodString[3] += 'ii.' - 'a';
sel = _sel_registerName«(char *)NXUniqueString(methodStrlng);
/liE U
if «(self responds'l'o:sel]1 (
(self per[orm,sel with,dest];
else (
obj ec t_se tIns tanceVar iable (self, methodStr lng, des t) ;
)
HeIse
[self perform,sel with:dest];
ltendiE
return self;
@end
Nessage transport
ffdefine RO_'l'ELL_MSG_ID {232323)
ffdefine HOj,SK_MSG_ID (323232)
Ildefille RO_REPLY_MSG_ID (233223 l
ffdefine DEFlI.UUCTIMEOU'r (15000)
static void remoteReply(port_t rPort, mS9_header_t *msg, int tilneout):
~~
(sel f
5,481,721
39
40
static void handleRemoteJ\sk (lIu:;g_header_t *msy, por t_t sender, id communication) {
;*
pAt-form il remote RPC.
•• This function may call many callouts to ellableRemoteListeJllng and
,. t!isalJ.leHemoteListening as it recurses .
•• exceptions may arise.
*;
NXJ\Loll1
itI
NXPortSLream
char
it!
sm,
int
Hell1oteHethodlllfo
illL
char
seltJame;
volatile result = nil;
'stream = NXOpenDecodePortStream(msg, communication);
'args;
self;
sell
errorCode = 0;
'sellnfo;
sequence = NXGetPortstreamSequence (streatu) ;
buffer[MSG_SIZE_MJ\X];
wi:Jrlling("ill rell1oteJ\nswer received packet\Il");
NXReat!Port1ypes(stream, "@%", &self, &selName);
warning("in remoteJ\nswer selName=%s\n", selName);
sel = seJ_getUlt!( (char .) selNamel;
if (! sell error ("handleHemoteJ\sk: received message with unknown sel");
se11n£o = [self remoteNethodlnfo:sel);
args = [sellnro decodeMethodParalllsFrolll:stream);
NXCloseDecot!ePortStream(stream);
if (i args) I errorCode = -2; goto done; )
NX_DURING
result = objc_lIIsgSendv(self, sel, [sellnfo sizeOfParams], al-gs);
NX_IIIINDI,ER
HOI,og (. * •• Error while excuting remote message for [Ox%x %s ..• ] \n", self, selName
) ;
errorCode = -1;
NX_END!lIINDLEH;
free(args);
f' let's encode the result 'f
done:
f' we cannot reuse msg here, regrettably, because if we come from DPSClient, we don't
have all OK buffer but a copy only big enough for the incoming rilSg; sigh * f
IlIsg = llI1sg_header_t ')buffer;
stream = NXOpenEncodePortStream(llIsg, sequence, COllullunicationl;
NX\·rriteport'lypes (stream, "i", &errorcode);
(sel1n[0 encodeHethodRet:result onto:stream];
NXCloseEllcodePot-tStreall1 (stream);
remoteHep.J.y(senuer, msg, (Collununication')"ollunullicationl->timeoutl;
warni ng ( "in remoteJ\nswer made return packet \n" ) ;
static void handleRemoteTell (msg_header_t 'msg, port_t sender, id cOl1ununication)
const char
NXPortStream
char
id
SEI,
int
Rell1oteMethodlnfo
'selName;
'stream " NXOpenDecodePortStream(msg, communication);
*args;
self;
sel;
volatile errorCode
0;
'sellnfo;
warning ( "in handleRemote'l'ell received packet \n" ) I
NXIlei:1dPort'lypes (str.eam, "@'l;", &sel[, &selNall1e) I
walllillg (" in halldleRel11ote1'ell selName=%s\n", selNall1e);
sel = sel_getUid {(char .) selNamel,
if I! sel) error ("handleRemoteTell: received message with unknown sel");
5,481,721
41
42
sellll10 = (self rellloLeNethodlnfo:se1j;
alg1' = [se11n[0 decodel1ethodParamsFrolll,sLream];
NXCloseDecodePorLStream (stream);
if (! argsl ( error Code = -2; goLo dOlle; )
NX_LJUHING
objc_msgSendv(se1f, sel, [sellnfo sizeOfPararns], args):
NX_IIl\NLJLER
errorcocle = -1;
NX_ENDIIANDLER;
free(args);
dOlle:
if (errorCode) warning("·** Error executing handleRemoteTell %d\n", errorcode);
illL rellloLe~!eSsageRecei
veCounL = 0;
static void handlel1emoteMessage(msg_header_t 'msg, void 'userDaLa) {
porL_L
sender = msg->rnsg_rernote_porl.;
lei
COllllllllllicatioll =" [Cornlllunical.ioll findCollllllForl'orl.:senderJ:
.if (! COllllllllnicatioll) [
syslog(LOG_EHH, "Received message h'orn zombie"};
return;
)
rernotel1essagel1eceivecounL++;
if (msg->msg_id == 110_'1'£LL_I1SG_1O) {
handleHemoteTell (msg, sender, cOllllllunication);
e1,:e if (llIs9->ms9_id == RO_ASK_MSG_ID) (
handleHernotel\sk (msg, sender, cOllllllunication);
else
syslog (LOG_EHR, "Bogus remote message") ;
° //
Hf
Should work, but has never been used/tested
static void relliote'l'ell{port_t target, msg_header_t 'msg, port_t sender, illt timeout) {
inL err, sm]Options = SEND_SWITCH;
llIsg->lilsg_remote_port = target;
msg->msg_local_port = sender;
IIIsg->msg_id = RO_'1'ELL_MSG_ID;
if (timeout >= 0)
sndOptiolls 1= SEND_TIl1Eou'r;
err = lllsg_send(msg,sndOptions,timeout);
if (err) error("remoteTell: cannot send");
}
.lIendH
static void remoteReply (port_t rPort. msg_header_t *msg, int timeout)
int err, sndOptions = SEND_S~IITC/I;
msg->ms9_remote_port = rPort;
Illsg->lllsg_local_port = PORT_NULL;
msg->msg_id = RO_REPLY_MSG_ID;
if {timeout >= O}
sndOptions 1= SEND_TIMEOUT;
err = msg_send{msg,sndOptions,timeout);
if (err) error ("remotel1eply: cannot send");
{
static nestingLevel=O:
static void remoteAsk(port_t target. msg_header_t 'msg, int timeout)
int err;
int volatile sndOptions = SEND_SWITCH;
int volatile rcvOptions = ReV_NO_SENDERS I RCV_INTERRUp'r;
msg->Illsg_remote_port = target;
{
5,481,721
44
43
JIISY·'>H1S<.l_loCilJ_"ort = replyPort;
msg->lI1sg_id = RO_ASK_MSG_ID;
i f (Llllleout >= 0) (
slldOptions 1= SEND_TI;,mOUT;
lcvOptions 1= RCV_TINEOUT;
)
nestingLevel++;
.
if (nestingLevel == 1 && enableProc)
( • enableProc) (reply Port, handleRemotel-lessage, NO) ;
!'iX_DUllING
eT.T = lIlsg_send (msg, sndOptions, timeout) ;
if: (err) error("remoteAsk: cannot send");
else {
while (1) (
l11Rg->lIIsg_size = MSG_SIZE_MAX;
IIlsg->msg_local-port = replyl'ort;
err = msg_receive{msg,rcvOptions, timeoutl;
H
(err)
(
ROLog{"remoteAsk: canllot receive or tilileout\n");
NX_IU\ISE ('l'IMEOUT_REMOTE_EXCEPTION, "Cannot receive", NULL);
else {
if (l11sg->msg--,id ==' RO_HEPI,Y_MSG_ID) {
break;
else
hanclleRel110teMessage «(lllsg_headel---.t ~) msg, NULL);
In? IF OU'!' OF LINE, DEl\LLOCN!'E IlERE
}
nestingLevel--;
if (InestingLevel && enableProc)
I ~eIlableProc) I replyPort, handleRemotel1essage, YES) ;
NX_'IIlWJ/JEH
Ilcstillgl.,evel-- ;
if I! nesting/.,evel && cnableProc)
("enableProc) (replyPort,halldleRemoteMessage, YES);
NX HEHAJSE
NX_ENO[!ANOLE:n;
I):
5,481,721
45
46
/* This module simply allows NXStl-ings to be passed across iJddress spaces.
The prillciple is: to encode a NXString, make a temporary object holding the string, encode
its clwracters, [ree the temporary: to decode a NXString, decode the temporary obj ect, re
place by an illunutable string, free the temporary. "I
ffimport " .. /lowlevel.subproj/NXString.h'
ilimport "HemoteObject.h"
II import ." NXPortStream. h'
ililllport
#import
@interface _1'emporaryString!lolder: Object (
(:!puo.Lic
NXstring
*string;
J
@elld
@implemellLation _'I'emporaryStringHolder
- wriLePortStream: (NXPortStream *)stream (
length ~ [string length];
lI11siyned
NXChiJr
"chars ~ malloc (lengtit"sizeof (NXChar) ) ;
{super writePortStream: stream]:
.
[std.l1y setChars:charsJ;
NXWri tePortTypes (stream, "i', &length);
NXPol·tEncodeBytes(streaJll, (char *Jchars, length):
[ree(chars) :
reLurn self:
- readportStream: (NXPorLStream *) stream {
unsigned
length:
NXChar
"chars:
[super readportStream: stream]:
NXHendPort'!'ypes (stream, • i', &length) I
ch"l:s ~ mal Joe (length*sizeof (NXChar)) :
NXPorLDecoeJeBytes(stream, (char *)chars, length);
string = [NXlnillnJtableString newFor:length chars:chars]:
[ree (chars):
return self;
- afLerportHeading: (communication *) conununication {
NXString
"res = string;
[self [reel I
return reSI
@end
@interface NXString (NXString_RemoteObject_Coding}
- encodeRemotelyFor: (Conununication *)conununication freel\fterEncoding:{BOOL *}flag;
f1emJ
@implemelltatioll NxString (NXString_Remoteobject_Coding)
- encodeRemotelyFor: (Communication *)conununication freeJ\[terEncoding:(BOOL ")f1ag {
_'['8Illporarystringtlolder
*new = !-'l'emporaryStringllolder new];
5,481,721
47
new-->sLrillg = self;
"flag = YES;
return Hew;
@end
48
5,481,721
49
50
*1
ffimpOl.L
Himport
nimport
extern sm, _sel_registerName(STR key);
//?7 will go away
Definitions
typedef struet _NXPortStream {
msg_header_t
*msg;
//77 DO SIZE '1'E5'1' LATER
BOUL
write:
id
con~unieation;
char
"chars:
int
nbchars;
int
maxehars;
int
*ints;
int
nbints;
int
maxints;
NXPortStream;
/" writing vs reading */
// HEMOVE AF'l'ER DEBUG J
@illterface Object (Co~unication_Calls)
- be [oreEllcoding , object onto, (NXPortstream *) stream freeAfterEncoding, (BOOL .) flag;
/* will encode the returned object: if flag is set. returned object will be send 'free
nfl:et: elicodiIlg .. /
- afterlJecoding, object [rom: (NXl'ortStream ") stream;
/* will replace the decoded object by the returned object "/
@end
global operations
extern NXPortStream "NXOpenEncodeportStream{llIsg_header_t "msg. int sequence. id communicat
ion) ;
extern NXPortStream "NXOpenDecodePortStream (msg_header_t "l1Isg. id cOllununication);
/" bu [fer is char [MSG_SIZE_MAX] ;
1£ mode is NX_WHI'l'EONLY. creates a NXPortStream, ready for writing. given a physic
al stream on which to actually put the bytes. If mode is NX_REAOONLY. creates a NXPortStre
am. ready for reading, given a physical stream on which to actually get the bytes. The ca
11e1- is responsible for closing physical. If the file format mismatches right (rom the st
art ,,,i til stream fOLillat. NULL is returned. otherwise an exception might be raised.
1ff read, have buffers point to msg */
extern void NXCloseEncodePortStream(NXPortStream "stream);
/" Copy buffers into message and prepare !nsg for msg_send;
free stream "/
extern void NXCloseDecodePortStream(NXPortStream *streaml;
/" free stream */
extern int NXGetPortStreamsequence(NXPortStream 'stream);
Read/Write data
void NXPortEncodeDytes(NXPortStream .stream, canst char "bytes. int count);
5,481,721
51
52
'1
Ilimport
flimport
Himport
extern SEL _sel_registerName!STR key);
II?? will go away
Definitions
typedef struct _NXPortStream {
msg_header_t
'msg;
I I 7? DO SIZE TEST Ll\'rER
1l00Lwrite;
id
COJ1l1J1unication:
char
'chars;
illt
nbchars:
int
maxchars:
illt
nbints;
nt
/IREMOVE IIF'Z'ER DEOUGl
*iIltSI
int
I ' writing vs reading °1
maxints;
j
NXPortStream;
@interface Object (Communication_Calls)
- ueforeEncoding: object onto: (NXPortStrearn ') stream freehfterEncoding: (DOOL .) flag:
I ' will encode the returned object; if flag is set, returned object will be send' free
after: encoding '1
- aftelDecoding: object from: (NXPortStream ' j stream;
I ' will r"eplace the decoded object by the returned object ./
@ell(l
global operations
extern NXPortStream 'NXOpenEncodeportStream(msy_header_t 'msy, int sequence, id cOJ1ununicat
ion);
extern NXPortStream 'NXOpenDecodePortStream(1I1sy_header_t 'msg, id cOl1ununicationl:
It buffer is char[MSG_SIZE_MIIX];
If mode is NX_WRITEONLY, creates a NXPortStream, ready for writing, given a physic
al stream on which to actually put the bytes. If mode is NX_HEIlDONLY, creates a NXPortStre
am, ready for reading, given a physical stream on which to actually get the bytes. 'I'he ca
ller is responsible for closing physical. If the file format mismatches right from the st
art with stream format, NULL is returned. otherwise an exception might be raised.
Iff read, have buffers point to msg '1
extern void NXCloseEncodePortStream(NXPortStream 'streaml:
I' Copy uuffers into message and prepare msg for msg_send;
free stream */
extern void NXCloseDecodePortStream(NXPortStream 'stream);
1* free stream '/
extern int NXGetPortStrealoSequence (NXPortStream *stream):
Read/Write data
void NXPortEncodenytes(NXPortStream 'stream, const char *bytes, illt count);
5,481,721
53
54
void NXPorlUecude13yles (NXPol-lStream "stream, char 'byles, int counL);
extern void NXwriteportTypes(NXPortStream *stream, canst char 'type, ... J;
/' Hestricted to monochar type descriptions;
r,ast arguments specify addresses of values to be written.
It might seem surprising to specity values by address, but this is extremely conve
nlenl for copy-paste with NXReadPortTypes calls. A more uown-to-the-earth cause fo'r this
passillg of addresses is that values of arbiLrary size is not well supported in ANSI C for
(unctiollS with variable number of arguments. "j
extern void NXReadPor.t'l'ypes(NXPortStream 'stream, canst char • type, ••• J;
j' Restricted to monochar type descriptions:
[,ast arguments specify addresses of values to be read. Expected type is checked a
gaillst LlIP. Lype actually present on the streiJm. */
exLeLlI vuid NXWritePortTypeIl1Lernal (NXPortSL~eaJl1 'stream, canst char "type, canst void 'da
tal ;
extern vuid NXHeadPort'l'ypelnternal(NXPortStream *stream, canst char 'type, void 'data);
/
** .. **11:* ••
errors
/* several exceptions can occur;
the format of all exceptions raised is a label, a message
string and maybe some extra information *j
ffdefine I'OH'l'S'l'HEl\l-CEmWH_BASE 370UO
j' less than appkit base *j
typedef ellum _PortStreamErrors (
POHTS'l'HBI\M_CI\I.LER_ERROR = POR'1'S'l'REAM_ERROR_BASE,
I'OH'l'S'l'RI';i\M_INCONSI S'l'ENCY,
l'OH'l'STHEI\~CIN'l'ERNAL_ERROI\
PortStreamErrorSI
einter.[ac:e Object (Object_PortStreaIlLCalls)
- wrltel'orl:Sl:reiJIll: (NXPortStream *J stream;
- readl'ortStream: (NXPortStream *) streaml
@end
5,481,721
55
/'
56
UXl'urL!;Lre
~stdarg.h>
~libc.h>
Hde[ine DEBUG_LEAKS
0
Utilities
static void BUG(CUllst char *6tr) {
sysloq (J,OG_ERR, • **" RemoteObjects: internal error in %s', str);
HX_Hi\lSE (POR'l'S'l'REAM_IN'!'EHNAL_ERROR, str, NULL);
static vuid checkExpected(const char *read'lype, const char *wallted) {
if (read'lype ='" wanted) return;
if {! read'lype II stl"Cmp (readType, wanted)) BUG("checkExpected");
@implementation object (Object_PortStream_Calls)
- writePortStream: (NXPortStream *) stream { return self; }
- readPortStJ:"eam: (NXPortStream *) stream ( return self; )
@end
Definitions
typedef struct _remote_message_t (
msg_header_t
header;
msg_type_t
sequenceType;
int
sequence;
1* following is chars type and chars, int types and ints, etc .. , *1
remote_J1lessage_t;
static
1*
static
/*
void PortlnternalWriteobject(NXPortstream *stream, id object);
write an object without header */
id PortlnternalReadObject(NXPortStreaw *stream);
read an object without header */
Coding data
void NXPortEncoueBytes(NXPortStream *stream, const char *buf, illt count)
while (streaw->ubchars + count> stream->maxchars) (
stream->maxchars += stream->maxchars + IJ
stream->chars = realloc{stream->chars, stream->maxchars);
}
IJcopylbu[. stream->chars "' stream->nbchars, count);
stream->nbchars +'" count;
void NXPortDecodeBytes(NXPortStream *stream, char *buf, int count) {
5,481,721
57
58
if (count> stream->llbcllars) BUG("NXPOI-UJecodel3ytes"):
JJCoPY (stream->chars, bur, count):
stream->chars += count:
sLream->nbchars -= count:
static inline void _NXEncodeChar{NXPortStream ·stream, signed char cll) {
if (stream->nbchars + 1 > stream->maxchars) (
stream->maxchars += stream->maxchars + 1;
[:Lreilln-;>chars = realloc (sLream->chal-s, sLreiun-;>ll1axchars);
)
stream->chars[stream->nbchars ++1 = Chi
static inline signed char _NXlJecodeChar{NXPortStream ·stream)
i f (stream->nbc!lars-- <= 0) BUG{"_NXDecoueChar");
returll *(stream->chars ++):
static void _NXEncodelnt{NXPortStream *stream, int x)
i [ (st ream->IIl>ints + 1 > stream->maxillts) (
stt-eal11->l11axints += stream->maxints + 1;
sLream->ints = realloc{stream->ints, stream->maxints * sizeof{int»;
)
sLream->ints[stream->nbints++] = x;
static int _NXDecodelnt{NXPortStream *stream) (
i [ (stream->nbints- - <= 0) BUG (" _NXDecodelnt") ;
l-eturll * (stream->illts++);
static void _NXEncodeBool(NXlJortStream *stream, BOOL x) (
_NXEllcouelnt (stream, (x) 7 1 : 0) I
static BOOI.. _NXDecoueBool (NXPortStream *stream)
lnL
x = _NxDecodelnt{stream):
if (x && xl=l) BUG{"_NXDecodeBool");
return x;
static illiine void _NXEncodeFloat{NXPortStream *stream, float x) {
NXPortEncodeByteslstream, (char *) &x, sizeoflfloat»;
static inline float _NXDecodeFloat(NXPortStream *stream)
floaL
x,
NXPor-LDecodeByteslstream, (char *) &x, sizeof{float»;
return x,
static inline void _NXEncodeDouble(NXPortStream *stream, double x) {
NXPorLEncodeBytes(stream, (char *) &x, sizeof(double»;
static inline double _NXDecodeDouble (NXPortStream *stream) {
double
XI
NXPorLDecodeBytes(stream, (char *) &x, sizeof{douule»;
return x;
static void _NXEncodeChars(NXPortStream *stream, const char *str) {
_NXBncodeBool (stream, (str) 7 YES : NO) I
5,481,721
59
60
if (Stl) (
int
len = strlen (str);
_NXEncodelnt (stream, len);
NXPorlEncodeBytes (stream, , str, len);
static char *_NxlJecodeChars(NXPortStream *stream)
if( J _NXlJecodeBool (stream» return NULL;
else (
,
iat
len", _NXDecodelnt(stream);
char
*str '" (STR) malloc (len+l) ;
NXl.'ortDecodeBytes (stream, str, len):
stl' [len]' '" '\0';
return str;
static NXJ\tom _NXDecodeuniqueString(NXPortstream *stream) (
chat'
*new
_NXDecodeCllars(stream);
NXJ\tolll
atom
NXUniqueString(new);
(ree(n8w);
return atom;
global operations
**Ic****/
NXPortStl'eam *NxOpenEncodePortStream(msg_header_t *msg, lnt sequence, id cOlmlUnication) (
NXl'ortStream
*stream = calloc(sizeof(NXPortStream), 1);
remoLe_lIIessage_t
*heacl '" (remote_/llessage_t *)msg;
if (! communication) BUG ("NXOpenEncodePortStream") ;
sLream->communicatioIl = cOllunullication;
strearn->write '" YES;
stream->msg = msg;
head ->sequenceType. msg_type_name
MSG_'l'YPE_IN'l'EGER_3 2 ;
head->sequenceType.msg_type_size
sizeof(int) * 0;
head- >sequence'1'ype .msg_type_nwl1ber
1;
heml->sequence'lype.msg_type_inline '" 'l'RUE;
head->sequence'rype.msg_type_longform = FJ\LSE;
head - >sequence'lype. msg_type_c1eallocate = Fl\LSE;
head->sequence '" sequence;
return stream;
NXPortStream *NXOpenUecoelePortStream (msg_header_t *msg, iel conununication)
void
*head '" «(void *)msg) +sizeof(remote_message_t);
NXPortStream
*stream = calloc (sizeof (NXPorlStream), 1);
1 [ (! communication) BUG ("NXOpenDecodePot-tStream") ;
stl-eam->conmlUllication = conullunication;
stream->write '" NO;
stream->msg = msg;
i[
(msg->msg_slmple)
msg_type_t
*type;
type '" head;
if (type->msg_type_name 1= MSG_TYPE_BYTE)
BUG("NXOpenDecodePortStream-char");
nU"Cillll- >nbchars '" type->msg_type_number I
head += sizeof(msg_type_t) J
stream->chars '" head;
head += stream->nbchars;
5,481,721
61
62
Lype = head;
(l:ype- :>l11s9_lype_"ullle ! = HSG_'l'YPr:;_lN'J'EGElC32)
BUG(WNXOpenDecodePortStream-inL W
);
sLrearn->nbints = type->ll1S9_type_llumuer;
head "I = sizeof (mS9_type_t) ;
stream->ints = head;
head += stream->nbints • sizeof(inL);
j [
else {
lllsy_type_long_t
• type;
Lype = head;
i f (type->msg_type_long_nallle 1= HSG_'fYPE_BY'fE)
IJUG(WNXOpenDecodePortStream-char W
);
sLream-:>nuclJars = type->msg_type_lOlI9_"umber";
.lwad += sizeof(msg_type_long_L);
sLream->c!Iars = «(char ")head) {OJ;
head
sizeo[(int);
.=
type = head;
i f (type->ll1sg_type_long_nallle J = HSG_'l'YPE_IN'l'EGER_32)
BUG{WNXOpenDecodePortstream-inL W
);
stream-:>nbints = type->msg_type_lon9_nullIber;
head += sizeofCmsg_type_lon9_t);
sLream->ints = {lint ")head) [0];
head += sizeof(int);
)
return stream;
void NXcloseEncodePortStream(NXPortStream 'stream)
void
*head"= «(void *)stream->msg)+sizeof(remote_message_t);
if (! strealll-:>wriLe) BUG(wNXCloseEllcodel'orlSl:realH");
/ . \'Ie pad chars Lo a multiple o[ 4; whaL a hack! '/
sLrr"illH->n!Jchars = ((sLream->nbchars + 3) /4) *4;
sLr"eal11->chars = realloc (Gtream->chars, stream->nbchars);
/* We test [or out-of-line '/
streilln->msg-:>msg_silllple = {sizeof(remote_message_t)+sizeof(msg_type_t)+streall1->nbchars
.sizeof(msg_type_t)+stream->nbints * sizeofCintl < MSG_SIZE_MAX) && (stream->nbchars <= 40
95) && (strealll->nblnts <= 4095);
if (stream->msg->msg_simple) (
msg_type_t
*type;
type = head;
type->lI1sg_type_name
MSG_'l'YPE_BY'l'E;
Lype->msg_type_size
8;
Lype-:>lIlsg_type_number = stream->nbchars;
Lype->msg_type_inline = TRUE;
type->msg_type_longform'= FALSE;
Lype->msg_Lype_deallocate = FALSE;
head += sizeof Cmsg_type_t) ;
bcopy(stream->chars, head. stream->nbchars);
head += stream->nbchars;
free(stream->chars);
type = head;
type->msy_type_I1ame
MSG_TYPE_IN'l'EG8R..32;
Lype->msg_type_size
sizeoflint) * 0;
type->lI1sg_type_number
strea"!->nbints;
Lype->msg_Lype_inline = '!'RUE;
type->msg_type_long[orrn = FALSE;
type->msg_type_deallocate ,. FALSE!
head += sizeof (rnsg_type_t) ;
5,481,721
63
64
J)f:OJly{S'Lr€rllll··;>illl:S,
IIp.Cld
I~
h(~ad.
~;l,ei1I11->fIl.J.iJ1Ls
stteC:HII-;--rll)illl.H
'"
~;.i zeaL (lrlL)};
.. sizeu[ (inc);
[reeisLrearn->intsJ;
else [
IIIsg_type_long_t
"type;
vm_address_t
buffer;
Lype = head;
Lype->lI1sg_type_header.rnsg_type_name
0:
t:ype->J1lsg_type_header .rnsg_type_size
0;
Lype->msg_type_header.I1Isg_type_number
0;
I.YP(?->IIIS'Lt.ype_header .Illsg_type_illliile = FlII,SI,;
I ype->rnsy_type_header .msg_type_lollg[orm = 'I'HUR;
t.ype->JI1sg_type_header .msg_type_deallocate = 'rHUS;
Lype->rnS\Ltype_Jong_name = 11SG_'!'YPE_IJY'I'E;
Lype->JIls~_type_long_r:;ize
= 0;
type->msy_type_long_number = sLream->nbc!1ars;
head += sizeof (msg_type_long_t J ;
i.f (vrn_allocate(task_self(), (vm_address_t "l&buffer-, stream->nbchars.
1)
!= KERN_
SUCCESS)
IJUG("NXCloseEncodel'ortStream: call't allocate (charsJ");
IJcopy(streall1->chars, (char "}buffer, streall1->nbchars);
((jilt ")head) [0] = buffer;
head 1= sizeof(int);
free(stream->chars);
type = head;
type->msg_type_header.msg_type_name
0;
type->msg_type_header.msg_type_size
0;
type->msg_type_header.msg_type_llumber
0;
type->Illsg_type_header.msg_type_inline = FALSE;
Lype->msg_type_header .msg_type_lollgforll1 = 'I'RUE;
Lype->Illsg_type_header.msg_type_ueallocate·= TRUE;
l:ype->lIIS\Ltype_] oll,Lname = 11SG_'l'YPE_UI'l'EGEH_32;
lype->Illsg_type_lollg_size = sizeof(inl) < 8;
tYPc->lIlsy_lype_long_nulllber = slream->nbints;
lieiJd. = sizeo[ (lIlsg_type_long_t) :
if (vm_allocate(task_self(), (vm_addr:ess_t <)&buffer. stream->Ilbints "sizeof(int)
!= KERN SUCCESS)
,11
DUG("NXCloseEncodeportStream: caB't allocate (ints)");
bcopy(strealll->ints, (char ")buffer. sLream->nbints " sizeof(intJ);
«(int ")head) [0] = buffer;
head += sizeof(int);
free(streall1->ints};
}
s t r'ealll->msg ->msg_type
strealll->msg->msg_size
MSG_TYPE_NORMAL;
head - (void ")stream->msg;
free (stream} ;
void NXCloseDecodePortStream(NXPortStream write) BUG ["NXCloseDecodePortStream") ;
if (! stream->msg->msg_simple) {
void
msg)+sizeof(remole_message_t);
msy_type_lony_t msg_type_long_name 1= MSG_TYPE_BYTE)
BUG("NXOpenDecodeportStream-char");
head l= sizeoflmsg_type_long_t);
.i( (vlll_deililocate(task_selfl) , llint *)head) [oJ, type->lIlsg_type_loug_number) 1= KB
,I.' ·,U.
HN_SUCCESS)
BUG("NXCloseDecodePortStream: can't deallocate (chars)");
5,481,721
65
head
66
6izeoflillt);
1=
type = head;
i f ltype->msg_type_long_name ! = NSG_TYPE_INTEGEI,-32)
BUG I "NXOpenVecodePortStream-int");
head • = sizeof (msg_type_long_t) ;
if (vlIJ_deallocate(task_seH(), ((inL ')head)[OJ. type->lIJsg_type_long_number' size
of (int»
! = KERN_SUCCESS)
BUG! "NXCloseDecodePortStream: call't deallocate (lnts)");
head ;= sizeof(int);
)
free (stream) ;
int NXGetPortStreamSequence(NXPortStream 'stream) (
rel1lote_,nessage_t
'he'lL! = (remote_lIlest4uge_t ') stream->msg;
retuln heau->sequellce;
j****".*
writing and reading arbitrary data
*******/
void NXWdtePortTypelnternal (NXPortStrealll 'stream. const char 'type, const void 'data) {
switch ("lype) {
case Ie': case 'e': {
char
cc = 0; I' for padding ,;
cc = '{(char ')data);
_NXEncodelnt (stream, cc);
break;
case's': case'S': (
short
ss = 0; I' for padding 'Iss = '! (short ')data);
_NXEucodelnt(stream, S6);
break;
}
case 'i': case 'I': case
_NXEncodelnt (stream,
bl-eak;
case
'
'1'~
case 'L / :
.) data) ) ;
* (lint
r' :
_NXEncodeFloat (stream, '( (float ") data) ) :
break;
case 'd':
_NXEncodeDouble(stream. '(double ')data»;
break;
case '@':
PortInternalWriteObject(stream, '(lid ')data»;
break;
case ' *, :
ff i f DEBUG_LEl\.KS
syslog(LOG_ElUl., .*** Remote Objects: un-freeable string encoding: %s', '( (char
**)data» ;
flendif
_NXEllcodeChars(stream, '((char ")datal):
break;
case' %':
_NXEncodeChars (sl:ream, * I (NXAtOlll *) data) ) ;
break:
case ' , ' , I
SEL
sel = '«SEL ')dalal:
char
'str = NULL;
if (sell str = sel_getName (sell r
_NXEncodeChars(stream. str);
break:
5,481,721
67
68
case' I ' ,
break:
default: BUG("NXWritePort'J'ypelnter11al: unknown type descriptor"l:
void NXReadPort'l'ypelnternal (NXPortStrearn *stream, const char *type, void *data) (,
switch (*typel I
case 'c': case 'C'; {
signed char
*ptr = data:
*ptr = _NXDecodelntlstreaml:
break:
case's': case , S'; {
short
*ptr = data:
'ptr = _NXUecodelnt (streaml :
break:
)
case 'i': case 'I': case '1': case 'L': I
111t
*ptr
data,
*ptr = _NXDecodelntlstreaml;
break:
=
I
case' f': I
float
*ptr = datal
*ptr = _NXDecodeFloat(streaml:
break:
)
case 'd': I
double
*ptr = data:
*ptr = _NXDecodeDoul.>Ie (stream) :
break:
)
case '@': I
1d
*ptr = data;
*ptr = PortlnternalReadObject(stream)
break;
I
)
case '*': (
char
**ptr = data:
*ptr = _NXDecodeChars(stream):
break:
)
case '%': (
NXl\tom
*ptr = data:
*ptr = _NXDecodeuniqueStr!ng(stream):
break:
}
case':': I
SEL
*ptr = data;'
NXl\tom
selName = _NXDecodeUniqueString(streaml:
*ptr = _sel_registerName«char *}selName);
break:
case '!'=
break:
default: BUG("NXReadPortTypelnternaI: unknown type descriptor" I
void NXWritePort'fypes (NXPortStream *stream, canst char *type, ... 1 (
va_list
args;
va_start (args, type);
I
5,481,721
69
70
could avoid I>, __,L :Line at the cost or more paillL'd tlebug "/
(stream, type) I
while ("type) {
NXwritePortTypelnternal {stream, type, va_arg (args, void AlII
type'" type++1 I· we restrict to monochar type descriptions AI
/ ' Ive
"_I~Xr-;ncotleChars
void NXneadPort'l'ypes(NXPort5tream "stream, constclIar ·type, ••. 1 {
NXlltom
reau'l'ypel
va~list
argsl
va_sLart{args, typell
read'l'ype '" _NXDecodeUniqueString{stream) I
I A \'Ie could avoid next line at the cost of more painful debug AI
cileckExpeeted{readType, type) I
,,,hile ("type) {
NXHeadPort'lypelnternal (stream, type, va_arg largs, vold .)) I
type = type++1 1* we restrict to monochar type descriptions AI
statIc void portlnternalWriteobject(NXPortStream 'stream, 1d object) (
BOor,
flag = NO:
if (! [stream->conunullicat.ion responds'l'o, @selector (beforeEncoding,onto,freell.fterEncod
illg:)J) BUG("PortlnternalWriteObject");
ouj eet '" lstream->conununication befol"eEnCoding, object onLo I stream freell.fterEllcoding,
&flagJ;
_NXEncodellool {stream, (objectl ? YES , NO) I
i f (object) {
Class
class = {Classl[object classJI
if (! class) BUG{"PortlnternalWriteObject: found null class'):
_NXEllcodeChars (stream. class->name);
[object writePortStream, streamJ I
_HXEncodeBool (stream, YES) I
if (flag) lobject freell
static id PortIllternalReadObject{NXPortStream *atream) {
id
object:
if (! _NxVecodeBool(stream» return nil:
else {
NXlI.tom className = _NXDecodeUniquestring (stream) I
Class
class = (Class) objc_getClass {(char .) className);
i[ II class) BUG{"portlnternalReadObject: class not loaded"):
/' explicil: class initializatioll "I
(void) [( idl class self J :
object = class_createlnstance (class, 0)1
[object readPortStrearn: streaml;
(object awakeJ:
if (1 [stream->conununication respolldS'l'OI Qselector (afterDecod1ng; from,) J) BUG (" Po
rtlnternalWriteObject-l")I
object = {stream->conununication afterDeCoding: object from, streamll
if (! _NXVecodeBool (stream» BUG (" Por-tIlIterllalReadObject-2') ;
return object;
5,481,721
71
We claim:
1. A method for sending an object oriented programming
language based message having dynamic binding from a
first object in a first process to a second object in a second
process, said method comprising the steps of:
transmitting, using a first processing means, said object
oriented programming language based message to a
first proxy in said first process;
using said first proxy and said first processing means,
encoding said object oriented programming language
based message into an operating system based message
at run time;
transmitting said operating system based message to said
second process in said second processing means at run
time;
decoding, using a second process, said operating system
based message into a language based message;
transmitting, using said second processing means, said
object oriented programming language based message
to said second object in said second process;
executing said object oriented programming language
based message by said second object in said second
process.
2. The method of claim 1 further including the steps of:
said second object in said second process and generating
an object oriented programming language based result;
encoding, using said second processing means, said object
oriented programming language based result into an
operating system based result at run time;
transmitting, using said second processing means, said
operating system based result to said first process at run
time;
decoding said operating system based result into an object
oriented programming language based result at run
time, using said first processing means;
transmitting, using said first processing means, said object
oriented programming language based result to said
first object.
3. The method of claim 1 wherein said object oriented
programming language based message comprises a method
and an argument.
4. The method of claim 1 wherein said second object
executes said method on said argument when executing said
message.
S. The method of claim 1 wherein the step of executing
said object oriented programming language based message
further includes the steps of:
said second object determining, using said second processing means, whether additional information is
needed to execute said object oriented programming
language based message;
said second object generating, using said second processing means, an object oriented programming language
based query if it is determined that additional information is needed;
encoding, using said second processing means, said object
oriented programming language based query into an
operating system based query at run time if it is
determined that additional information is needed;
transmitting said operating system based query to said
first process at run time, using said second processing
means if it is determined that additional information is
needed;
decoding, using said first processing means, said operating system based query into an object oriented pro-
72
gramming language based query at run time if it is
determined that additional information is needed;
transmitting, using said first processing means, said object
oriented programming language based query to said
first object if it is determined that additional informa5
tion is needed.
6. The method of claim 5 further including the steps of:
said first object generating, using said first processing
means, an object oriented programming language based
10
reply to said object oriented programming language
based query;
encoding said object oriented programming language
based reply into an operating system based reply at run
time, using said first processing means;
15
transmitting, using said first processing means, said operating system based reply to said second process at run
time;
decoding, using said second processing means, said operating system based reply into an object oriented pro20
gramming language based reply at run time;
transmitting, using said second processing means, said
object oriented programming language based reply to
said second object.
25
7. The method of claim 6 wherein said first processing
means and said second processing means are the same
processing means.
8. The method of claim 1 wherein said object oriented
programming language based message comprises an objec30 tive C message.
9. The method of claim 1 wherein said operating system
based message comprises a Mach message.
10. The method of claim 1 wherein said first proxy
represents said second object.
35
11. A method for sending an object oriented programming
language based message having dynamic binding from a
first object in a first process to a second object in a second
process, said method comprising the steps of:
transmitting, using a first processing means, said object
oriented programming language based message to a
40
first proxy in said first process;
using said first proxy and said first processing means,
encoding said object oriented programming language
based message into an operating system based message
45
at run time;
transmitting, using said first processing means, said operating system based message to said second process at
run time;
decoding, using said second processing means, said oper50
ating system based message into an object oriented
programming language based message at run time;
transmitting, using said second processing means, said
object oriented programming language based message
to said second object;
55
said second object generating an object oriented programming language based query, using said second
processing means;
creating, using said second processing means, a second
60
proxy in said second process;
transmitting, using said second processing means, said
object oriented programming language based query to
said second proxy;
using said second proxy and said second processing
65
means, encoding said object oriented programming
language based query into an operating system based
query at run time;
5,481,721
74
73
transmitting, using said second processing means, said
operating system based query to said first process at run
time;
decoding, using said first processing means, said operating system based query into an object oriented programming language based query at run time;
transmitting, using said first processing means, said object
oriented programming language based query to said
first object;
said first object generating an object oriented programming language based reply, using said first processing means;
encoding, using said first processing means, said object
oriented programming language based reply into an
operating system based reply at run time;
transmitting, using said first processing means, said operating system based reply to said second process at run
time;
decoding, using a second processing means, said operating system based reply into an object oriented programming language based reply at run time;
transmitting, using said second processing means, said
object oriented programming language based reply,
using said second processing means, and generating an
object oriented programming language based result;
encoding, using said second processing means, said object
oriented programming language based result into an
operating system based result at run time;
transmitting, using said second processing means, said
operating system based result to said first process at run
time;
decoding, using said first processing means, said operating system based result into an object oriented programming language based result;
transmitting, using said first processing means, said object
oriented programming language based result to said
first object.
12. The method of claim 11 wherein said object oriented
programming language based message comprises a method
and an argument.
13. The method of claim 12 wherein said second object
executes said method on said argument when executing said
message.
14. The method of claim 11 wherein said first process and
said second process are located on first and second computers respectively.
15. The method of claim 11 wherein said object oriented
programming language based message comprises an objective C message.
16. The method of claim 11 wherein said operating system
based message comprises a Mach message.
17. The method of claim 11 wherein said first proxy
represents said second object.
18. The method of claim 11 wherein said second proxy
represents said first object.
19. A method for sending, in a C environment with
minimal run time support, an object oriented programming
language based message having dynamic binding from a
first object in a first process to a second object in a second
process, said method comprising the steps of:
transmitting, using a first processing means implementing
said C environment, said object oriented programming
language based message to a first proxy in said first
process;
using said first proxy and said first processing means,
encoding said object oriented programming language
5
10
15
20
25
30
35
40
45
50
55
60
65
based message into an operating system based message
at run time;
transmitting said operating system based message to said
second process at run time;
decoding, using a second processing means implementing
said C environment, said operating system based message into a language based message;
transmitting, using said second processing means, said
object oriented programming language based message
to said second object.
20. The method of claim 19 further including the steps of:
said second object executing said object oriented programming language based message, using said second
processing means, and generating an object oriented
programming language based result;
encoding, using said second processing means, said object
oriented programming language based result into an
operating system based result at run time;
transmitting, using said second processing means, said
operating system based result to said first process at run
time;
decoding said operating system based result into an object
oriented programming language based result at run
time, using said first processing means;
transmitting, using said first processing means, said object
oriented programming language based result to said
first object.
21. The method of claim 20 wherein the step of executing
said object oriented programming language based message
further includes the steps of:
said second object determining, using said second processing means, whether additional information is
needed to execute said object oriented programming
language based message;
said second object generating, using said second processing means, an object oriented programming language
based query if it is determined that additional information is needed;
encoding, using said second processing means, said object
oriented programming language based query into an
operating system based query at run time if it is
determined that additional information is needed;
transmitting said operating system based query to said
first process at run time, using said second processing
means if it is determined that additional information is
needed;
decoding, using said first processing means, said operating system based query into an object oriented programming language based query at run time if it is
determined that additional information is needed;
transmitting, using said first processing means, said object
oriented programming language based query to said
first object if it is determined that additional information is needed.
22. The method of claim 21 further including the steps of:
said first object generating, using said first processing
means, an object oriented programming language based
reply to said object oriented programming language
based query;
encoding said object oriented programming language
based reply into an operating system based reply at run
time, using said first processing means;
transmitting, using said first processing means, said operating system based reply to said second process at run
time;
5,481,721
75
76
decoding, using said second processing means, said oper24. The method of claim 21 wherein said first processing
ating system based reply into an object oriented promeans and said second processing means are the same
gramming language based reply at run time;
processing means.
transmitting, using said processing means, said object
oriented programming language based reply to said 5
second object.
* * * * *
23. The method of claim 21 wherein said operating
system based message comprises a Mach message.
Disclaimer: Justia Dockets & Filings provides public litigation records from the federal appellate and district courts. These filings and docket sheets should not be considered findings of fact or liability, nor do they necessarily reflect the view of Justia.
Why Is My Information Online?