123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777 |
- /* $TOG: README /main/4 1999/08/30 10:44:07 mgreess $ */
- 1.8 10/27/92
- Copyright (c) 1992 by Sun Microsystems, Inc.
- TOOLTALK IMPLEMENTATION OVERVIEW
- This document presents a roadmap to understanding the implementation
- of the main message-passing features of ToolTalk 1.0.1. It does not
- aim to describe the details of the algorithms used. In order to find
- these out it is necessary to read the source code as well as the
- comments. This document should give the reader an overall picture of
- how all the various objects that implement message-passing fit
- together as well as familiarity with where to find the code that
- implements a particular feature. Finally some naming conventions used
- throughout the code are given.
- ********** Please update this document as the code is changed **********
- MEMORY MANAGEMENT
- The only memory management policy used througout the code is
- reference-counting. This is an automatic sort of memory management
- since objects are "magically" deleted when there are no longer
- references to them. This functionality is implemented by way of
- pointer classes that behave just like normal pointers except that they
- maintain a reference count in the object they point to. It is
- important *not* to mix normal pointers with counted pointers.
- MIXING POINTERS
- You should never use a C pointer with refcounted objects (i.e., those
- inheriting from _Tt_object (actually, from _Tt_new; I have no idea why
- _Tt_new and _Tt_object are different)). You should always use
- refcounting pointers ("ptrs") with _Tt_objects. The danger is as
- follows:
- _Tt_object *evilRef;
- {
- evilRef = new _Tt_object;
- //
- // refCount is now zero, but evilRef is pointing at our
- // object!
- //
- ...
- _Tt_object_ptr goodRef = evilRef;
- //
- // refCount is now 1
- //
- ...
- //
- // goodRef goes out of scope.
- // goodRef::~_Tt_object_ptr() decrements the refCount
- // to zero, and deletes our object because the
- // refCount is now zero.
- //
- }
- int foo = evilRef->dataMember; // core dump
- If you need a static pointer to a _Tt_object, you cannot have a static
- _Tt_object_ptr, because static C++ instances aren't allowed. But you
- don't want to have a static _Tt_object *, because then you have to
- eternally worry about never showing it to a refcounting pointer (which
- would try to delete it when it was done with it).
- The best thing to do is have a static _Tt_object_ptr *:
- static _Tt_object_ptr *ppGlobalObj;
- ppGlobalObj = new _Tt_object_ptr;
- *ppGlobalObj = new _Tt_object;
- Now you can use *ppGlobalObj wherever you would have used your static
- _Tt_object_ptr. The _Tt_object you allocated is safely refcounted, so
- you can let refcounting pointers do whatever they want with it.
- When it's time to clean up, you just
- delete ppGlobalObj;
- This is a call to ppGlobalObj->~_Tt_object_ptr(), which decrements the
- refcount of your object, and *optionally* deletes it if the refcount
- is zero. This way, you don't delete your object out from under anyone
- who still has a reference to it.
- REFCOUNTING INSIDE CONSTRUCTORS
- Inside a constructor, never assign the 'this' pointer of a refcounted
- object to an automatic refcounting pointer. Inside the constructor,
- the refcount is still zero. Assigning 'this' into a refcounting
- pointer will increment the refcount to 1. But before the constructor
- returns, the automatic refcounting pointer on the stack will be
- destructed. The destructor will decrement the object's refcount back
- to zero, and therefore delete the object -- before the constructor
- even returns!
- _Tt_foo::_Tt_foo()
- {
- // On entry, _Tt_foo::_refcount_ == 0
- _Tt_foo_ptr evilRef = this;
- // Now, _Tt_foo::_refcount_ == 1
- ...
- // On exit, evilRef->~_Tt_foo_ptr() will be called.
- // It will decrement the refcount to zero, and
- // then delete this object under construction!
- }
- Also, be sure not to pass the 'this' pointer to any routine that might
- hold a temporary reference to the object while the routine runs.
- (Here, "hold a temporary reference to" means "increment the refcount
- and then decrement it".) If you must pass the 'this' pointer anywhere
- from within the constructor, cast it to const first so that the
- compiler will protect you from any routine with an intention of
- modifying its refcount. If you absolutely must pass the 'this'
- pointer to a routine that might only temporarily reference it, then
- manually increment the refcount before doing so, and then manually
- decrement the refcount before returning from the constructor
- CYCLICAL REFERENCES
- Avoid creating data structures that permit cyclical references.
- A single reference cycle can cause a massive memory leak.
- COMMENT CONVENTIONS
- Throughout the code, any comments preceded by XXX: denote notes to the
- reader of problems or suggestions for the code they describe.
- DESCRIPTION OF OBJECT CLASSES
- This section presents all the object classes used to implement the
- message-passing portion of ToolTalk along with a brief description of
- what each class represents and in which files it can be found. Before
- describing the classes we need to mention some important naming
- conventions as well as some general comments about client/server
- conventions.
- Many of the object classes described below have client-side and
- server-side implementations. For example, a client-side version of a
- ToolTalk message has methods to send the message to the server. On the
- server-side there is a corresponding _Tt_message that processes the
- new message. In the 1.0 version of ToolTalk, these methods were
- roughly coded as:
- void _Tt_some_object::
- sample_method(...)
- {
- if (_tt_mp->in_server()) {
- ... do server-specific actions ...
- } else {
- ... do client-specific actions ...
- }
- }
- where the "in_server" method for the _Tt_mp class returns 1 if the
- environment is in server mode (which is true if the method is
- executing on behalf of ttsession). The problem with this scheme is
- that the library was excessively big because the code to implement the
- server, ttsession, was contained in the library even though it wasn't
- needed for the clients.
- Because of this, the 1.0.1 version split up this method in one of two
- ways. The first method is to create two subclasses of the object. One
- of the subclasses, named with a "_c_" infix, represents the
- client-side state and methods for the object. The other subclass,
- named with a "_s_" infix, represents the server-side state and methods
- for the object. Each of these subclasses then contains the
- corresponding method which now doesn't need the conditional test. The
- example above then becomes:
- void _Tt_c_some_object::
- sample_method(...)
- {
- ... do client-specific actions ...
- }
- void _Tt_s_some_object::
- sample_method(...)
- {
- ... do server-specific actions ...
- }
- The other mechanism is to still have one object class but name the
- object with a "c_" prefix for the client-specific method, and an "s_"
- prefix for the server-specific method.
- In the 4/93 version of ToolTalk, more classes were split up so that
- no references to server-only classes would appear in client code.
- As part of this, the client-to-server XDR methods were slightly
- changed. You will see (in mp_rpc_implement.C) that apparently
- the server uses a XDR function to decode the arguments of some
- RPCs which is different from the encoding XDR function. This
- seemingly violates the central dogma of XDR, but it really isn't
- as bad as it looks. What is happpening is that we have class
- hierarchies like:
- _Tt_pattern
- |
- ------------------
- | |
- _Tt_s_pattern _Tt_c_pattern
- Only _Tt_pattern has an XDR method -- that is, the data that appears
- on the wire is only the common data. A client would create a _Tt_c_pattern
- and XDR it out; the server then XDR's it in as a _Tt_s_pattern, but
- the _Tt_pattern::XDR routine does all the work and the only difference
- is the virtual function table (and any private _Tt_s_pattern data,
- which would be initialized by the _Tt_s_pattern constructor.)
- The following classes are related to the main message-passing
- functionality in ToolTalk. Details on what methods they implement and
- precise algorithms are in the source code along with the comments
- throughout the code.
- Class: _Tt_arg
- File: tt/lib/mp/mp_arg.C (client/server methods)
- tt/lib/mp/mp_s_arg.C (server-only methods)
- This class represents an argument to a message or pattern. Its methods
- implement matching arguments with other arguments and constructing and
- updating arguments.
- Class: _Tt_auth
- File: tt/lib/mp/mp_auth.C (client/server methods)
- tt/lib/mp/mp_auth_functions.C (utility functions copied from libICE)
- This class maintains the authorization level being used by the server
- (cookie, des, unix, none). In the case of the cookie authorization
- scheme, this class also is responsible for generating the cookie and
- writing it to and reading it from the authority file.
- Class: _Tt_desktop
- File: tt/lib/mp/mp_desktop.C
- This class represents "desktop" sessions. Currently this means X11
- server sessions but the methods reflect an interface that is largely
- independent of X11. As a result, all X11-dependent code is isolated in
- this one module.
- Class: _Tt_c_message (subclass of _Tt_message)
- File: tt/lib/mp/mp_c_message.C
- This class represents client-only view of ToolTalk messages. It
- contains methods for sending messages to the ttsession server.
- Class: _Tt_c_procid (subclass of _Tt_procid)
- File: tt/lib/mp/mp_c_procid.C
- This class implements client-only methods needed to reply to messages
- and to retrieve new messages for the ToolTalk client represented by
- this class.
- Class: _Tt_file
- File: tt/lib/mp/mp_file.C (server/client methods)
- tt/lib/mp/mp_s_file.C (server-only methods)
- This class represents file objects. The functionality implemented is
- for querying for specs contained in the file, joining and quitting
- file scopes, and queuing and de-queueing messages on file objects.
- Class: _Tt_message
- File: tt/lib/mp/mp_message.C
- This class represents a ToolTalk message. This class represents
- methods that are common to both clients and ttsession. Its subclasses,
- _Tt_s_message and _Tt_c_message described below implement methods
- specific to client manipulation and server manipulation respectively.
- The code is structured so that _Tt_message objects contain the methods
- to do delivery to other clients.
- Class: _Tt_mp
- File: tt/lib/mp/mp_mp.C
- This class represents the global state needed by the message-passing
- objects. In particular, this object contains many object caches that
- are needed by the system as well as holds references to some important
- objects such as the default session object.
- Class: _Tt_node
- File: tt/lib/mp/mp_node.C
- This class represents a ToolTalk spec. Its methods create/destroy
- specs in a database and add properties to an existing spec.
- Class: _Tt_observer
- File: tt/lib/mp/mp_observer.C
- This class is a very simple class that basically just stores some
- message fields that can change for static observers of a message. It
- is used only by the _Tt_s_message class. This class is mainly used as
- to hold the information necessary to honor static observer "promises"
- for message disposition processing.
- Class: _Tt_otype
- File: tt/lib/mp/mp_otype.C
- This class implements methods needed to deal with otype definitions.
- In general the operations needed are for setting and returning the
- observer, inherited, and handler signatures for this otype definition
- as well as printing out the otype definition which, in addition to
- debugging, is used to print out the definition for storage under the
- Classing Engine and also for dumping out compiled type databases in
- source format.
- Class: _Tt_pattern
- File: tt/lib/mp/mp_pattern.C (server/client methods)
- tt/lib/mp/mp_s_pattern.C (server-only methods)
- This class represents a ToolTalk pattern. Client-side methods
- implement adding/deleting fields to the pattern and
- registering/unregistering the pattern by invoking the proper rpc
- routines on the server. Server-side methods implement the appropiate
- actions for registering/unregistering patterns as well as matching
- patterns to messages.
- Class: _Tt_procid
- File: tt/lib/mp/mp_procid.C
- This class represents a ToolTalk client. It represents all of the
- methods and data necessary for sending a message to a ToolTalk client.
- Its subclasses, _Tt_s_procid and _Tt_c_procid, implement the needed
- server-only and client-only methods.
- Class: _Tt_ptype
- File: tt/lib/mp/mp_ptype.C
- This class implements methods needed to deal with ptype definitions
- and with starting new instances of ptypes which is functionality
- needed to implement the start disposition options for ToolTalk
- messages. Also, as with _Tt_otype objects, printing methods are also
- defined that are used for storage in type databases and dumping out
- ptype definitions in source format.
- Class: _Tt_rpc_client
- File: tt/lib/mp/mp_rpc_client.C
- This class represents a client rpc connection. The methods implemented
- are basically wrappers around the rpc interfaces with the important
- difference that the api to this object is the same regardless of
- whether tli rpc or non-tli rpc is used. The methods for this object
- are ifdefed to use tli rpc or not.
- Class: _Tt_rpc_server
- File: tt/lib/mp/mp_rpc_server.C
- This class represents an rpc server. The methods implemented are
- wrappers around the rpc server interfaces with the difference that
- both tli and non-tli rpc is supported by ifdefing the implementation
- code for the methods to select which rpc interface to use.
- Class: _Tt_s_message (subclass of _Tt_message)
- File: tt/lib/mp/mp_s_message.C
- This class represents a ToolTalk message with some specialized methods
- that are specific to server-side manipulation of messages. In
- particular this class implements methods to dispatch a message (ie.
- match the message against static patterns), and deliver the message to
- ToolTalk clients with patterns that match it. There are also methods
- to implement the reliability for messages that don't match any active
- client's patterns.
- Class: _Tt_s_mp
- File: tt/lib/mp/mp_s_mp.C
- This class represents the global server-only state needed by the
- message-passing objects. It contains object caches that are relevant
- to the server module as well as the ptypes and otypes that were read
- in from the type database.
- Class: _Tt_s_procid (subclass of _Tt_procid)
- File: tt/lib/mp/mp_s_procid.C
- This class implements server-only methods needed to send messages to
- ToolTalk clients and also methods which process replies to previously
- sent messages.
- Class: _Tt_session
- File: tt/lib/mp/mp_session.C (server/client methods)
- tt/lib/mp/mp_s_session.C (server-only methods)
- This class represents a ToolTalk session. It has methods that apply in
- client-side and server-side environments. The main functionality
- required is establishing ToolTalk sessions, advertising the addressing
- information to contact the session, and methods for connecting to a
- session given its addressing information and auto-starting a session
- if necessary.
- Class: _Tt_signature
- File: tt/lib/mp/mp_signature.C
- This class represents a ToolTalk signature which can be either an
- otype or ptype signature. The main methods for this object allow one
- to create a signature, match the signature against an operation name
- and a list of arguments, and match the signature against relevant
- message fields.
- Class: _Tt_stream_socket
- File: tt/lib/mp/mp_stream_socket.C
- This class represents a stream connection. Its methods are ifdefed
- depending on whether TCP sockets are to be used or TLI streams.
- Class: _Tt_typedb
- File: tt/lib/mp/mp_typedb.C
- This class represents the ToolTalk type database. It has methods for
- reading and writing the database in either a native xdr format or to
- the Classing Engine. Important Note: since the typedb on disk is
- a table_ptr and not just a table, it's possible to have a null
- table and a non-null _ptr, which if xdr-decoded will crash the
- _Tt_object_table xdr method, because the default constructor
- for that class tries to decode a null table.
- Class: _Tt_global
- File: tt/lib/util/tt_global_env.C
- This class is where any global information that is not specific to
- message-passing is kept. In particular any global flags or caches are
- kept in this object. This class also keeps the number representing the
- current xdr version to be used by all xdr methods.
- Class: _Tt_host
- File: tt/lib/util/tt_host.C
- This class packages up methods for mapping host addresses to host
- names and viceversa.
- Class: _Tt_xdr_version
- File: tt/lib/util/tt_xdr_version.C
- This class provides a mechanism for temporarily setting the default
- xdr version. It sets the version to a given number in the constructor
- and then resets the default to the previous value in the destructor.
- Class: _Tt_new_ptr
- File: tt/lib/util/tt_new_ptr.C
- Generic version of a pointer class. This implements the
- reference-counting machinery. See declare_ptr_to and implement_ptr_to
- in tt/lib/util/tt_ptr.h to see how a specialized pointer class is
- derived from this generic class.
- Class: _Tt_object_list
- File: tt/lib/util/tt_object_list.C
- Generic version of a list class. See declare_list_of and
- implement_list_of in tt/lib/util/tt_list.h to see how a specialized
- list class is derived from the generic one.
- Class: _Tt_object_table
- File: tt/lib/util/tt_object_table.C
- Generic version of a table class. See declare_table_of and
- implement_table_of in tt/lib/util/tt_table.h to see how a specialized
- list class is derived from the generic one. Important note: unfortunately
- you can crash this method by trying to de-xdr on online db because
- the default constructor for that class tries to decode a null table.
- FINDING ONE'S WAY AROUND
- The rich functionality offered by ToolTalk is implemented partly in
- the client library, partly in the server (which itself is implemented
- by objects contained in a server library). Thus it isn't always
- trivial to find which code implements a certain feature. A good
- heuristic to use is to decide whether the particular feature is likely
- to be implemented on the client side or server side. If it is likely a
- client-side feature then it is accessible through one of the tooltalk
- api calls. These are all implemented in the tt/lib/api/c directory
- where the files are named api_<noun> where <noun> is the name of the
- entity being operated on by the api call. For example,
- tt_pattern_create can be found in "api_pattern.C". The api calls that
- don't operate on a particular entity are found in "api_mp.C". For
- example, tt_open and tt_fd can be found there.
- Once the code for the api is located, the way the feature is
- implemented can be traced through the code. Occasionally the api call
- may interact with the server-side code. This is usually in the form of
- an api call such as:
- ...
- rstatus = call(TT_RPC_JOIN_SESSION,
- (xdrproc_t)tt_xdr_procid,
- (char *)&procid,
- (xdrproc_t)xdr_int,
- (char *)&status);
- ...
- This will cause an rpc stub to be invoked which then invokes the
- appropiate methods on the server side. All the rpc stubs are
- implemented in tt/lib/mp/mp_rpc_implement.C. Furthermore, the naming
- scheme for these stubs is to add an underscore to the front of the
- enum used to make the call on the client side and then turn all the
- letters into lower case. In the example above, one would then look for
- the "_tt_rpc_join_session" function in tt/lib/mp/mp_rpc_implement.C.
- The details of how the call is mapped to this rpc stub and what
- processing goes on before the rpc stub is invoked can be found in the
- _tt_service_rpc function which does the actual rpc dispatching.
- Since most of the functionality is initiated by an api call (the
- exception being the initializiation of the server itself), this
- strategy usually succeeds in finding the code one is looking for.
- We now list some guides into the code implementing some of the major
- features in ToolTalk. For each piece of functionality some important
- methods and/or files are listed which represent the main code that
- implements the given functionality. Looking at the code for the given
- methods and their associated comments should give a good idea as to
- how the functionality is implemented.
- ********** Please add to this list **********
- - RPC REQUEST HANDLING
- (client) _Tt_session::call - single method that all other methods use
- when they want to invoke an rpc call.
- (server) tt/lib/mp/mp_rpc_implement.C contains all of the rpc stubs
- that get invoked on the server side in response to an rpc request from
- a client. The dispatch function in this file "_tt_service_rpc" does
- the actual dispatching of the rpc request (_tt_service_rpc is actually
- invoked by the rpc function svc_getreqset which is called from
- _Tt_s_mp::main_loop by calling _Tt_rpc_server::run).
- Looking at the various rpc stubs in mp_rpc_implement.C is an
- excellent way of navigating the code to find out how each particular
- rpc call is used. In particular, a good strategy for finding out how
- an api call is implemented is by looking at the definition of the api
- call and tracing through the code until _Tt_session::call invocations
- are found. Using the rpc procedure number passed into the
- _Tt_session::call method one can then look in mp_rpc_implement.C to
- see what happens on the server side.
- - NULL MESSAGE SENDING/RECEIVING LOOP
- This loop consists of a client sending a request message to ttsession
- when no patterns match the message. The message gets failed and
- returned to the sender. Understanding the code involved in this loop
- means that one understands the basic low-level mechanism by which the
- messages sent to and received from ttsession. The major methods
- involved here are:
- (client) _Tt_c_message::dispatch - send message to ttsession
- (server) _Tt_s_message::dispatch - match message with static patterns.
- (server) _Tt_s_message::deliver - match message with dynamic patterns.
- (server) _Tt_s_procid::add_message - add a message to procid's message
- queue.
- (server) _Tt_s_procid::signal_new_message - signal a procid that it has
- a new message.
- (client) _Tt_c_procid::next_message - get next message from ttsession
- (server) _Tt_s_procid::next_message - return next message from ttsession
- - DISPATCHING AND DELIVERING A MESSAGE
- (server) _Tt_s_message::dispatch
- (server) _Tt_s_message::deliver
- - STARTING A NEW PTYPE
- (server) _Tt_s_message::handle_no_recipients
- (server) _Tt_s_message::change_state
- (server) _Tt_ptype::start
- - PROCESSING THE REPLY TO A MESSAGE
- (client) _Tt_c_procid::update_msg
- (server) _Tt_s_procid::update_msg
- (server) _Tt_message::update_msg
- (server) _Tt_s_message::change_state
- - HONORING START AND QUEUE RELIABILITY OPTIONS
- _Tt_s_message::deliver
- _Tt_s_message::handle_no_recipients
- For file-scope messages, queueing is actually handled on the client
- side. For more details look in:
- _Tt_c_message::c_dispatch
- _Tt_file::q_message
- _Tt_file::dq_message
- _Tt_file::c_join
- - READING IN CLASSING ENGINE DATABASES
- _Tt_typedb::init_ce
- - ADDING/MERGING NEW TYPES TO A TYPE DATABASE
- _Tt_typedb::begin_write
- _Tt_typedb::end_write
- _Tt_typedb::insert_ptype
- _Tt_typedb::insert_otype
- - DECLARING A PTYPE
- _tt_rpc_declare_ptype
- _Tt_s_procid::declare_ptype
- - DETECTING PTYPE LAUNCH FAILURE
- sig_handler (in tt/bin/ttsession/mp_server.C)
- notify_launch_failure (in tt/bin/ttsession/mp_server.C)
- _Tt_ptype::launch_failed
- - AUTO-STARTING A SESSION
- tt_open (tt/lib/api/c/api_mp.C)
- _Tt_mp::init
- _Tt_session::init
- _Tt_session::c_init
- - ESTABLISHING RPC CONNECTION TO THE SERVER
- _Tt_session::client_session_init - client-side processing
- _Tt_s_mp::main_loop - unix and network rpc connection
- _Tt_session::u_rpc_init - unix socket rpc connection
- - XDR/RPC VERSIONING SCHEME
- _tt_service_rpc (tt/lib/mp/mp_rpc_implement.C)
- _Tt_xdr_version (tt/lib/util/tt_xdr_version)
- _Tt_global::set_xdr_version (tt/lib/util/tt_global_env.C)
- _Tt_global::xdr_version (tt/lib/util/tt_global_env.C)
- - TRACE/DEBUG/ERROR OUTPUT
- For trace output in ttsession and in slib, use the _Tt_trace
- class.
- For debug output in the old dm code, do it according to the
- $TT_DM_DEBUG level. No other module has a similar debug output
- facility.
- When an error is detected in the client library and a Tt_status
- other than TT_ERR_INTERNAL is going to be passed up through
- the API to diagnose it, then the client library should not
- emit any message anywhere. That's the job of the application using
- libtt.
- _tt_syslog( 0, LOG_ERR, ) should be used in the client library when:
- - a TT_ERR_INTERNAL (bug) arises and we want to diagnose what happened;
- - a partial failure of an API call occurs, but the API call is still
- considered to have succeeded. For example, when tt_message_send()
- for a file-scoped message cannot contact one of the interested
- sessions.
- The daemons (ttsession and dbserver) should pass either 0 or stderr
- to _tt_syslog(), depending on whether they are in daemon mode or not.
- In CDE, certain parts (tt_type_comp, ttrm et al.) of ToolTalk are
- likely to be run from tools that have stderr aimed at /dev/null.
- These parts of ToolTalk should never write to stderr directly, nor
- call perror(), nc_perror(), t_error(), etc. Instead, they should pass
- stderr to _tt_syslog(), and use strerror() (or %m), nc_strerror(),
- t_strerror(), etc. _tt_syslog() will prefix, route, suppress, and
- multiplex the output appropriately. For example, in CDE we will
- probably multiplex our error output onto ~/.dt/errorlog. For
- suppression, _tt_syslog() obeys _tt_global->silent.
- No output should include un-internationalized English. The output
- should include only ToolTalk-ese and catgets() strings. (ToolTalk-ese
- can be C/C++ use of the ToolTalk API, or the ToolTalk types language.)
- All modules that call catgets() should include "util/tt_gettext.h", so
- that they are really calling _tt_catgets() instead of the one in
- /usr/lib. This lets us map catgets() to something else on platforms
- where it is not supported.
- It is OK to write normal output to stdout.
- ASSIGNING NEW CATGETS MESSAGE IDS
- When you code up a new call to catgets(), choose your message set out
- of util/tt_gettext.h, and use -1 as the message id. Then follow this
- procedure to update the message catalog:
- 0. Make sure your source file(s) is(are) checked in; ttgenmsg will
- refuse to work on checked-out files.
- 0a. Make sure /home/tooltalk/tools/bin is in your PATH
- 1. Check out SUNW_TOOLTALK.msg and SUNW_TOOLTALK.sets
- 2. Run "make msgs" from the top of the tree.
- 2a. Run msgfix which will sort and clean up "msgs" into "msgs.fixed"
- 3. Check in SUNW_TOOLTALK.sets (which now has been updated).
- 4. Copy "msgs.fixed" to SUNW_TOOLTALK.msg and check it in.
- 5. Check in your updated source files.
- Note to source customers: ttgenmsg depends on genmsg, an internal
- SunSoft tool, and so ttgenmsg is not included in the ToolTalk source
- distribution. If you add any new catgets() messages, you will have to
- manually assign message ids and update the message catalog.
- Note to ToolTalk developers: ttgenmsg and genmsg are in
- /home/tooltalk/tools/bin.
- THREADING ISSUES
- - Locking granularity:
- ToolTalk API calls acquire a global lock which they hold as long
- as they are doing operations that can't block. The original
- intention was to drop the locks around RPC calls and re-acquire
- them immediately after returning from such calls. This proved to
- be unworkable because it resulted in crashes in the RPC library.
- As of the time of this writing, locks are held around RPC calls,
- which introduces the danger of a blocking call causing a deadlock
- in the entire TT library, since only one thread is actually
- manipulating TT structures at any particular time in a process.
- - ttsession threading
- Currently ttsession only uses a thread for registering as a client
- of itself. This is an atomic operation and its success or failure
- doesn't have a significant effect on ttsession's ability to serve
- client processes. ttsession tracing won't work until the
- thread completes successfully.
- - ALL thread-specific storage should be from malloc calls, NEVER local
- storage. Also, all storage obtained from tt_malloc-type calls is
- thread-specific.
- - Calling tt_message_receive and receiving the same message simultaneously
- in different threads causes the message object to be updated from under
- the calling code. This happens, for instance, when one thread has a
- handle pattern registered and another has an observe pattern registered,
- and they both match the same message. The biggest danger here is
- if one thread deletes a message while another thread is accessing
- data from the message. It is up to the client program to regulate
- access to TT message data.
|