diff options
Diffstat (limited to 'xpa/doc/server.html')
-rw-r--r-- | xpa/doc/server.html | 833 |
1 files changed, 0 insertions, 833 deletions
diff --git a/xpa/doc/server.html b/xpa/doc/server.html deleted file mode 100644 index 2e10b11..0000000 --- a/xpa/doc/server.html +++ /dev/null @@ -1,833 +0,0 @@ -<!-- =defdoc xpaserver xpaserver 3 --> -<HTML> -<HEAD> -<TITLE>XPA Server API</TITLE> -</HEAD> -<BODY> - -<!-- =section xpaserver NAME --> -<H2><A NAME="xpaserver">XPAServer: The XPA Server-side Programming Interface</A></H2> - -<!-- =section xpaserver SYNOPSIS --> -<H2>Summary</H2> -A description of the XPA server-side programming interface. - -<!-- =section xpaserver DESCRIPTION --> -<H2><A NAME="intro">Introduction to XPA Server Programming</H2></A> -<P> -Creating an XPA server is easy: you generally only need to call the -XPANew() subroutine to define a named XPA access point and set up the -send and receive callback routines. You then enter an event loop such -as XPAMainLoop() to field XPA requests. -<PRE> - #include <xpa.h> - - XPA <A HREF="./server.html#xpanew">XPANew</A>(char *class, char *name, char *help, - int (*send_callback)(), void *send_data, char *send_mode, - int (*rec_callback)(), void *rec_data, char *rec_mode); - - XPA <A HREF="./server.html#xpacmdnew">XPACmdNew</A>(char *class, char *name); - - XPACmd <A HREF="./server.html#xpacmdadd">XPACmdAdd</A>(XPA xpa, - char *name, char *help, - int (*send_callback)(), void *send_data, char *send_mode, - int (*rec_callback)(), void *rec_data, char *rec_mode); - - void <A HREF="./server.html#xpacmddel">XPACmdDel</A>(XPA xpa, XPACmd cmd); - - XPA <A HREF="./server.html#xpainfonew">XPAInfoNew</A>(char *class, char *name, - int (*info_callback)(), void *info_data, char *info_mode); - - int <A HREF="./server.html#xpafree">XPAFree</A>(XPA xpa); - - void <A HREF="./server.html#xpamainloop">XPAMainLoop</A>(void); - - int <A HREF="./server.html#xpapoll">XPAPoll</A>(int msec, int maxreq); - - void <A HREF="./server.html#xpaatexit">XPAAtExit</A>(void); - - void <A HREF="./server.html#xpacleanup">XPACleanup</A>(void); - -</PRE> - -<H2>Introduction</H2> - -To use the XPA application programming interface, a software developer -generally will include the xpa.h definitions file: -<PRE> - #include <xpa.h> -</PRE> -in the software module that defines or accesses an XPA access point, and -then will link against the libxpa.a library: -<PRE> - gcc -o foo foo.c libxpa.a -</PRE> -XPA has been compiled using both C and C++ compilers. - -<P> -A server program generally defines an XPA access point by calling the -XPANew() routine and specifies "send" and/or "receive" callback -procedures to be executed by the program when an external process -either sends data or commands to this access point or requests data or -information from this access point. A program also can define several -sub-commands for a single access point by calling XPACmdNew() and -XPACmdAdd() instead. Having defined one or more public access points -in this way, an XPA server program enters its usual event loop (or -uses the standard XPA event loop). - -<!-- =defdoc xpanew xpanew 3 --> - -<!-- =section xpanew NAME --> -<H2><A NAME="xpanew">XPANew: create a new XPA access point</A></H2> - -<!-- =section xpanew SYNOPSIS --> -<B> -<PRE> - #include <xpa.h> - - XPA XPANew(char *class, char *name, char *help, - int (*send_callback)(), - void *send_data, char *send_mode, - int (*rec_callback)(), - void *rec_data, char *rec_mode); -</PRE> -</B> - -<!-- =section xpanew DESCRIPTION --> -<P> -Create a new XPA public access point with the class:name -identifier <A HREF="./template.html">template</A> -and enter this access point into the XPA name server, so that it -can be accessed by external processes. XPANew() returns an XPA struct. -Note that the length of the class and name designations must be less -than or equal to 1024 characters each. - -<P> -The XPA name server daemon, xpans, will be started automatically if it -is not running already (assuming it can be found in the path). The -program's ip address and listening port are specified by the -environment variable XPA_NSINET, which takes the form <ip>:<port>. If -no such environment variable exists, then xpans is started on the -current machine listening on port 14285. It also uses 14286 as a -known port for its public access point (so that routines do not have -to go to the name server to find the name server ip and port!) -As of XPA 2.1.1, version information is exchanged between the xpans -process and the new access point. If the access point uses an XPA -major/minor version newer than xpans, a warning is issued by both processes, -since mixing of new servers and old xpa programs (xpaset, xpaget, -xpans, etc.) is not likely to work. You can turn off the warning -message by setting the XPA_VERSIONCHECK environment variable to "false". - -<P> -The help string is meant to be returned by a request from xpaget: -<PRE> - xpaget class:name -help -</PRE> -<P> -A send_callback and/or a receive_callback can be specified; at -least one of them must be specified. - -<P> -A send_callback can be specified that will be executed in response to -an external request from the xpaget program, the XPAGet() routine, or -XPAGetFd() routine. This callback is used to send data to the -requesting client. - -<P> -The calling sequence for send_callback() is: -<PRE> - int send_callback(void *send_data, void *call_data, - char *paramlist, char **buf, size_t *len) - { - XPA xpa = (XPA)call_data; - ... - return(stat); - } -</PRE> -<P> -The send_mode string is of the form: "key1=value1,key2=value2,..." -The following keywords are recognized: -<PRE> - key value default explanation - ------ -------- -------- ----------- - acl true/false true enable access control - freebuf true/false true free buf after callback completes -</PRE> -<P> -The call_data should be recast to the XPA struct as shown. In -addition, client-specific data can be passed to the callback in -send_data. - -<P> -The paramlist will be supplied by the client as qualifying parameters -for the callback. There are two ways in which the send_callback() -routine can send data back to the client: - -<P> -1. The send_callback() routine can fill in a buffer and pass back a -pointer to this buffer. An integer len also is returned to specify the -number of bytes of data in buf. XPA will send this buffer to the -client after the callback is complete. - -<P> -2. The send_callback can send data directly to the client by writing -to the fd pointed by the macro: -<PRE> - xpa_datafd(xpa) -</PRE> -<P> -Note that this fd is of the kind returned by socket() or open(). - -<P> -If a buf has been allocated by a standard malloc routine, filled, and -returned to XPA, then freebuf generally is set so that the buffer will -be freed automatically when the callback is completed and data has -been sent to the client. If a static buf is returned, freebuf should -be set to false to avoid a system error when freeing static storage. -Note that default value for freebuf implies that the callback will -allocate a buffer rather than use static storage. - -<P> -On the other hand, if buf is dynamically allocated using a method -other than a standard malloc/calloc/realloc routine (e.g. using Perl's -memory allocation and garbage collection scheme), then it is necessary -to tell XPA how to free the allocated buffer. To do this, use the -XPASetFree() routine within your callback: -<PRE> - void XPASetFree(XPA xpa, void (*myfree)(void *), void *myfree_ptr); -</PRE> -The first argument is the usual XPA handle. The second argument is the -special routine to call to free your allocated memory. The third -argument is an optional pointer. If not NULL, the specified free -routine is called with that pointer as its sole argument. If NULL, the -free routine is called with the standard buf pointer as its sole -argument. This is useful in cases where there is a mapping between the -buffer pointer and the actual allocated memory location, and the -special routine is expecting to be passed the former. - -<P> -If, while the callback performs its processing, an error occurs that -should be communicated to the client, then the routine XPAError should be -called: -<PRE> - XPAError(XPA xpa, char *s); -</PRE> -<P> -where s is an arbitrary error message. The returned error message -string will be of the form: -<PRE> - XPA$ERROR [error] (class:name ip:port) -</PRE> -<P> -If the callback wants to send a specific acknowledgment message back -to the client, the routine XPAMessage can be called: -<PRE> - XPAMessage(XPA xpa, char *s); -</PRE> -<P> -where s is an arbitrary error message. The returned error message -string will be of the form: -<PRE> - XPA$MESSAGE [message] (class:name ip:port) -</PRE> -<P> -Otherwise, a standard acknowledgment is sent back to the client -after the callback is completed. - -<P> -The callback routine should return 0 if no error occurs, or -1 to -signal an error. - -<P> -A receive_callback can be specified that will be executed in response -to an external request from the xpaset program, or the XPASet (or -XPASetFd()) routine. This callback is used to process data received -from an external process. - -<P> -The calling sequence for receive_callback is: -<PRE> - int receive_callback(void *receive_data, void *call_data, - char *paramlist, char *buf, size_t len) - { - XPA xpa = (XPA)call_data; - ... - return(stat); - } -</PRE> -<P> -The mode string is of the form: "key1=value1,key2=value2,..." -The following keywords are recognized: -<PRE> - key value default explanation - ------ -------- -------- ----------- - acl true/false true enable access control - buf true/false true server expects data bytes from client - fillbuf true/false true read data into buf before executing callback - freebuf true/false true free buf after callback completes -</PRE> -<P> -The call_data should be recast to the XPA struct as shown. In -addition, client-specific data can be passed to the callback in -receive_data. - -<P> -The paramlist will be supplied by the client. In addition, if the -receive_mode keywords buf and fillbuf are true, then on entry into the -receive_callback() routine, buf will contain the data sent by the -client. If buf is true but fillbuf is false, it becomes the callback's -responsibility to retrieve the data from the client, using the data fd -pointed to by the macro xpa_datafd(xpa). If freebuf is true, then buf -will be freed when the callback is complete. - -<P> -If, while the callback is performing its processing, an error occurs -that should be communicated to the client, then the routine XPAError -can be called: -<PRE> - XPAError(XPA xpa, char *s); -</PRE> -<P> -where s is an arbitrary error message. - -<P> -The callback routine should return 0 if no error occurs, or -1 to -signal an error. - -<!-- =defdoc xpacmdnew xpacmdnew 3 --> - -<!-- =section xpacmdnew NAME --> -<H2><A NAME="xpacmdnew">XPACmdNew: create a new XPA public access point for commands</A></H2> - -<!-- =section xpacmdnew SYNOPSIS --> -<B> -<PRE> - #include <xpa.h> - - XPA XPACmdNew(char *class, char *name); -</PRE> -</B> - -<!-- =section xpacmdnew DESCRIPTION --> -<P> -Create a new XPA public access point for commands that will share a -common identifier class:name. Enter this access point into the XPA -name server, so that it can be accessed by external processes. -XPACmdNew() returns an XPA struct. - -<P> -It often is more convenient to have one public access point that can -manage a number of commands, rather than having individual access -points for each command. For example, it is easier to command the -ds9 image display using: -<PRE> - echo "colormap I8" | xpaset ds9 - echo "scale log" | xpaset ds9 - echo "file foo.fits" | xpaset ds9 -</PRE> -<P> -then to use: -<PRE> - echo "I8" | xpaset ds9_colormap - echo "log" | xpaset ds9_scale - echo "foo.fits" | xpaset ds9_file -</PRE> -<P> -In the first case, the commands remain the same regardless of the -target XPA name. In the second case, the command names must change -for each instance of ds9. That is, if a second instance of ds9 -called DS9 were running, it would be commanded either as: -<PRE> - echo "colormap I8" | xpaset DS9 - echo "scale log" | xpaset DS9 - echo "file foo.fits" | xpaset DS9 -</PRE> -<P> -or as: -<PRE> - echo "I8" | xpaset DS9_colormap - echo "log" | xpaset DS9_scale - echo "foo.fits" | xpaset DS9_file -</PRE> -<P> -Thus, in cases where a program is going to manage many commands, it -generally is easier to define them as commands associated with the -XPACmdNew() routine, rather than as separate access points using -XPANew(). - -<P> -When XPACmdNew() is called, only the class:name identifier is -specified. Each sub-command is subsequently defined using the -XPACmdAdd() routine. - -<!-- =defdoc xpacmdadd xpacmdadd 3 --> - -<!-- =section xpacmdadd NAME --> -<H2><A NAME="xpacmdadd">XPACmdAdd: add a command to an XPA command public access point</A></H2> - -<!-- =section xpacmdadd SYNOPSIS --> -<B> -<PRE> - #include <xpa.h> - - XPACmd XPACmdAdd(XPA xpa, char *name, char *help, - int (*send_callback)(), - void *send_data, char *send_mode, - int (*rec_callback)(), - void *rec_data, char *rec_mode); -</PRE> -</B> - -<!-- =section xpacmdadd DESCRIPTION --> -<P> -Add a command to an XPA command access point. The XPA argument specifies the -XPA struct returned by a call to XPANewCmd(). The name argument is the -name of the command. The other arguments function identically to the -arguments in the XPANew() command, i.e., the send_callback and rec_callback -routines have identical calling sequences to their XPANew() counterparts, -with the exceptions noted below. - -<P> -When help is requested for a command access point using: -<PRE> - xpaget -h class:name -</PRE> -<P> -all of the command help strings are listed. To get help for a given -command, use: -<PRE> - xpaget -h class:name cmd -</PRE> -<P> -Also, the acl keyword in the send_mode and receive_mode strings is -global to the access point, not local to the command. Thus, the value -for the acl mode should be the same in all send_mode (or receive_mode) -strings for each command in a command access point. (The acl for -send_mode need not be the same as the acl for receive_mode, though). - -<!-- =defdoc xpacmddel xpacmddel 3 --> - -<!-- =section xpacmddel NAME --> -<H2><A NAME="xpacmddel">XPACmdDel: remove a command from an XPA command public access point</A></H2> - -<!-- =section xpacmddel SYNOPSIS --> -<B> -<PRE> - #include <xpa.h> - - void XPACmdDel(XPA xpa, XPACmd cmd); -</PRE> -</B> - -<!-- =section xpacmddel DESCRIPTION --> -<P> -This routine removes a command from the list of available commands in -a given XPA. That command will no longer be available for processing. - -<!-- =defdoc xpainfonew xpainfonew 3 --> - -<!-- =section xpainfonew NAME --> -<H2><A NAME="xpainfonew">XPAInfoNew: define an XPA info public access point</A></H2> - -<!-- =section xpainfonew SYNOPSIS --> -<B> -<PRE> - #include <xpa.h> - - XPA XPAInfoNew(char *class, char *name, - int (*info_callback)(), - void *info_data, char *info_mode); -</PRE> -</B> - -<!-- =section xpainfonew DESCRIPTION --> -<P> -[NB: this is an experimental interface, new to XPA 2.0, whose value -and best use is evolving.] - -<P> -A program can register interest in receiving a short message about a -particular topic from any other process that cares to send such a -message. Neither has to be an XPA server. For example, if a user -starts to work with a new image file called new.fits, she might -wish to alert interested programs about this new file by sending a -short message using xpainfo: -<PRE> - xpainfo IMAGEFILE /data/new.fits -</PRE> - -<P> -In this example, each process that has used the XPAInfoNew() call to -register interest in messages associated with the identifier IMAGEFILE -will have its info_callback() executed with the following calling -sequence: -<PRE> - int info_cb(void *info_data, void *call_data, char *paramlist) - { - XPA xpa = (XPA)call_data; - } -</PRE> -<P> -The arguments passed to this routine are equivalent to those sent in -the send_callback() routine. The main difference is that there is no -buf sent to the info callback: this mechanism is meant for short -announcement of messages of interest to many clients. - -<P> -The mode string is of the form: "key1=value1,key2=value2,..." -The following keywords are recognized: -<PRE> - key value default explanation - ------ -------- -------- ----------- - acl true/false true enable access control -</PRE> -<P> -Because no buf is passed to this callback, the usual buf-related keywords -are not applicable here. - -<P> -The information sent in the parameter list is arbitrary. However, we -envision sending information such as file names or XPA access points -from which to collect more data. Note that the xpainfo program and -the XPAInfo() routine that cause the info_callback to execute do not -wait for the callback to complete before returning. - -<!-- =defdoc xpafree xpafree 3 --> - -<!-- =section xpafree NAME --> -<H2><A NAME="xpafree">XPAFree: remove an XPA public access point</A></H2> - -<!-- =section xpafree SYNOPSIS --> -<PRE> -<B> - #include <xpa.h> - - int XPAFree(XPA xpa); -</B> -</PRE> - -<!-- =section xpafree DESCRIPTION --> -<P> -Remove the specified XPA public access point from the name server and -free all associated storage. Note that removal from the name server -happens automatically when the process terminates, so this call is not -generally needed. It is used when public access points are being -defined temporarily and then destroyed when no longer needed. For -example, ds9 temporarily creates a public access point when it -loads a new image for display and destroys it when the image is -unloaded. - -<!-- =defdoc xpamainloop xpamainloop 3 --> - -<!-- =section xpamainloop NAME --> -<H2><A NAME="xpamainloop">XPAMainLoop: optional main loop for XPA</A></H2> - -<!-- =section xpamainloop SYNOPSIS --> -<B> -<PRE> - #include <xpa.h> - - void XPAMainLoop(); -</PRE> -</B> - -<!-- =section xpamainloop DESCRIPTION --> -<P> -Once XPA access points have been defined, a program must enter an -event loop to watch for requests from external programs. This can be -done in a variety of ways, depending on whether the event loop is -processing events other than XPA events. In cases where there are no -non-XPA events to be processed, the program can simply call the -XPAMainLoop() event loop. This loop is implemented essentially as -follows (error checking is simplified in this example): -<PRE> - FD_ZERO(&readfds); - while( XPAAddSelect(NULL, &readfds) ){ - if( sgot = select(swidth, &readfds, NULL, NULL, NULL) >0 ) - XPAProcessSelect(&readfds, 0); - else - break; - FD_ZERO(&readfds); - } -</PRE> -<P> -The XPAAddSelect() routine sets up the select() readfds variable so -that select() will wait for I/O on all the active XPA channels. It -returns the number of XPAs that are active; the loop will end when -there are no active XPAs. The standard select() routine is called to -wait for an external I/O request. Since no timeout struct is passed -in argument 5, the select() call hangs until there is an external -request. When an external I/O request is made, the XPAProcessSelect() -routine is executed to process the pending requests. In this routine, -the maxreq value determines how many requests will be processed: if -maxreq <=0, then all currently pending requests will be processed. -Otherwise, up to maxreq requests will be processed. (The most usual -values for maxreq is 0 to process all requests.) - -<P> -If a program has its own Unix select() loop, then XPA access points can -be added to it by using a variation of the standard XPAMainLoop: -<PRE> - XPAAddSelect(xpa, &readfds); - [app-specific ...] - if( select(width, &readfds, ...) ){ - XPAProcessSelect(&readfds, maxreq); - [app-specific ...] - FD_ZERO(&readfds); - } -</PRE> -<P> -XPAAddSelect() is called before select() to add the access points. -If the first argument is NULL, then all active XPA access points -are added. Otherwise only the specified access point is added. -After select() is called, the XPAProcessSelect() routine can be called -to process XPA requests. Once again, the maxreq value determines how -many requests will be processed: if maxreq <=0, then all currently -pending requests will be processed. Otherwise, up to maxreq requests -will be processed. - -<P> -XPA access points can be added to -<A HREF="./xt.html">Xt event loops</A> (using XtAppMainLoop()) -and -<A HREF="./tcl.html">Tcl/Tk event loops</A> (using vwait and the Tk loop). -When using XPA with these event loops, you only need to call: -<PRE> -int XPAXtAddInput(XtAppContext app, XPA xpa) -</PRE> -or -<PRE> - int XPATclAddInput(XPA xpa) -</PRE> -respectively before entering the loop. - -<!-- =defdoc xpapoll xpapoll 3 --> - -<!-- =section xpapoll NAME --> -<H2><A NAME="xpapoll">XPAPoll: execute existing XPA requests</A></H2> - -<!-- =section xpapoll SYNOPSIS --> -<B> -<PRE> - #include <xpa.h> - - int XPAPoll(int msec, int maxreq); -</PRE> -</B> - -<!-- =section xpapoll DESCRIPTION --> -<P> -It is sometimes desirable to implement a polling loop, i.e., where one -checks for and processes XPA requests without blocking. For this -situation, use the XPAPoll() routine: -<PRE> - XPAPoll(int msec, int maxreq); -</PRE> -<P> -The XPAPoll() routine will perform XPAAddSelect() and select(), but with a -timeout specified in millisecs by the msec argument. If one or more -XPA requests are made before the timeout expires, the XPAProcessSelect() -routine is called to process those requests. The maxreq value determines -how many requests will be processed: if maxreq < 0, then no events are -processed, but instead, the return value indicates the number of events -that are pending. If maxreq == 0, then all currently pending requests -will be processed. Otherwise, up to maxreq requests will be processed. -(The most usual values for maxreq are 0 to process all requests and 1 -to process one request). - -<!-- =defdoc xpaatexit xpaatexit 3 --> - -<!-- =section xpaatexit NAME --> -<H2><A NAME="xpaatexit">XPAAtExit: install exit handler</A></H2> - -<!-- =section xpaatexit SYNOPSIS --> -<PRE> -<B> - #include <xpa.h> - - void XPAAtExit(void); -</B> -</PRE> - -<!-- =section xpaatexit DESCRIPTION --> -<P> -XPAAtExit() will install an exit handler using atexit() to run XPAFree on all -XPA access points. This might be useful in cases where Unix sockets are being -used: if an explicit call to XPAFree() is not made by the program, the Unix -socket file will not be deleted immediately without an atexit handler. (NB: this -call should not be made in a Tcl/Tk application. Accessing the Tcl native file -system after Tcl has shut down all file systems causes the Tcl/Tl program to -crash). - -<!-- =defdoc xpacleanup xpacleanup 3 --> - -<!-- =section xpacleanup NAME --> -<H2><A NAME="xpacleanup">XPACleanup: release reserved XPA memory</A></H2> - -<!-- =section xpacleanup SYNOPSIS --> -<PRE> -<B> - #include <xpa.h> - - void XPACleanup(void); -</B> -</PRE> - -<!-- =section xpacleanup DESCRIPTION --> -<P> -When XPA is initialized, it allocates a small amount of memory for the -access control list, temp directory path, and reserved commands. This -memory is found by valgrind to be "still reachable", meaning that "your -program didn't free some memory it could have". Calling the -XPACleanup() routine before exiting the program will free this memory -and make valgrind happy. - -<!-- =defdoc xpamacros xpamacros 3 --> - -<!-- =section xpamacros NAME --> -<H2><A NAME="macros">XPA Server Callback Macros</A></H2> - -<!-- =section xpamacros SYNOPSIS --> -<B> -<PRE> - #include <xpa.h> - - xpa_class, xpa_name, xpa_method, xpa_cmdfd, xpa_datafd, - xpa_sendian, xpa_cendian -</PRE> -</B> - -<!-- =section xpamacros DESCRIPTION --> -<P> -Server routines have access to information about the XPA being called via -the following macros (each of which takes the xpa handle as an argument): -<PRE> - macro explanation - ------ ----------- - xpa_class class of this xpa - xpa_name name of this xpa - xpa_method method string (inet or local connect info) - xpa_cmdfd fd of command socket - xpa_datafd fd of data socket - xpa_sendian endian-ness of server ("little" or "big") - xpa_cendian endian-ness of client ("little" or "big" -</PRE> -<P> -The argument to these macros is the call_data pointer that is passed -to the server procedure. This pointer should be type case to XPA -in the server routine: -<PRE> - XPA xpa = (XPA)call_data; -</PRE> - -<P> -The most important of these macros is xpa_datafd(). A server routine -that sets "fillbuf=false" in receive_mode or send_mode can use this -macro to perform I/O directly to/from the client, rather than using -buf. - -<P> -The xpa_cendian and xpa_sendian macros can be used together to determine -if the data transferred from the client is byte swapped with respect -to the server. Values for these macros are: "little", "big", or "?". -In order to do a proper conversion, you still need to know the format -of the data (i.e., byte swapping is dependent on the size of the data -element being converted). - -<!-- =defdoc xparace xparace 3 --> - -<!-- =section xparace NAME --> -<H2><A NAME="race">XPA Race Conditions</A></H2> - -<!-- =section xparace SYNOPSIS --> -Potential XPA race conditions and how to avoid them. - -<!-- =section xparace DESCRIPTION --> -<P> -Currently, there is only one known circumstance in which XPA can get -(temporarily) deadlocked in a race condition: if two or more XPA -servers send messages to one another using an XPA client routine such -as XPASet(), they can deadlock while each waits for the other server -to respond. (This can happen if the servers call XPAPoll() with a -time limit, and send messages in between the polling call.) The -reason this happens is that both client routines send a string to the -other server to establish the handshake and then wait for the server -response. Since each client is waiting for a response, neither is able -to enter its event-handling loop and respond to the other's -request. This deadlock will continue until one of the timeout periods -expire, at which point an error condition will be triggered and the -timed-out server will return to its event loop. - -<P> -Starting with version 2.1.6, this rare race condition can be -avoided by setting the XPA_IOCALLSXPA environment variable for servers -that will make client calls. Setting this variable causes all XPA -socket IO calls to process outstanding XPA requests whenever the -primary socket is not ready for IO. This means that a server making a -client call will (recursively) process incoming server requests while -waiting for client completion. It also means that a server callback -routine can handle incoming XPA messages if it makes its own XPA call. -The semi-public routine oldvalue=XPAIOCallsXPA(newvalue) can be used -to turn this behavior off and on temporarily. Passing a 0 will turn -off IO processing, 1 will turn it back on. The old value is returned -by the call. - -<P> -By default, the XPA_IOCALLSXPA option is turned off, because we judge -that the added code complication and overhead involved will not be -justified by the amount of its use. Moreover, processing XPA requests -within socket IO can lead to non-intuitive results, since incoming -server requests will not necessarily be processed to completion in the -order in which they are received. - -<P> -Aside from setting XPA_IOCALLSXPA, the simplest way to avoid this race -condition is to multi-process: when you want to send a client message, -simply start a separate process to call the client routine, so that -the server is not stopped. It probably is fastest and easiest to use -fork() and then have the child call the client routine and exit. But -you also can use either the system() or popen() routine to start one -of the command line programs and do the same thing. Alternatively, you -can use XPA's internal launch() routine instead of system(). Based on -fork() and exec(), this routine is more secure than system() because -it does not call /bin/sh. - -<P> -Starting with version 2.1.5, you also can send an XPAInfo() message with -the mode string "ack=false". This will cause the client to send a message -to the server and then exit without waiting for any return message from -the server. This UDP-like behavior will avoid the server deadlock when -sending short XPAInfo messages. - -<!-- =section xpaserver SEE ALSO --> -<!-- =text See xpa(n) for a list of XPA help pages --> -<!-- =section xpanew SEE ALSO --> -<!-- =text See xpa(n) for a list of XPA help pages --> -<!-- =section xpacmdnew SEE ALSO --> -<!-- =text See xpa(n) for a list of XPA help pages --> -<!-- =section xpacmdadd SEE ALSO --> -<!-- =text See xpa(n) for a list of XPA help pages --> -<!-- =section xpacmddel SEE ALSO --> -<!-- =text See xpa(n) for a list of XPA help pages --> -<!-- =section xpainfonew SEE ALSO --> -<!-- =text See xpa(n) for a list of XPA help pages --> -<!-- =section xpafree SEE ALSO --> -<!-- =text See xpa(n) for a list of XPA help pages --> -<!-- =section xpacleanup SEE ALSO --> -<!-- =text See xpa(n) for a list of XPA help pages --> -<!-- =section xpamainloop SEE ALSO --> -<!-- =text See xpa(n) for a list of XPA help pages --> -<!-- =section xpapoll SEE ALSO --> -<!-- =text See xpa(n) for a list of XPA help pages --> -<!-- =section xpamacros SEE ALSO --> -<!-- =text See xpa(n) for a list of XPA help pages --> -<!-- =section xparace SEE ALSO --> -<!-- =text See xpa(n) for a list of XPA help pages --> -<!-- =stop --> - -<P> -<A HREF="./help.html">Go to XPA Help Index</A> - -<H5>Last updated: September 10, 2003</H5> -</BODY> -</HTML> |