home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / X / mit / extensions / lib / PEX / cp / phigsmon.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-07-21  |  13.9 KB  |  529 lines

  1. /* $XConsortium: phigsmon.c,v 5.9 92/08/10 20:46:54 eswu Exp $ */
  2.  
  3. /***********************************************************
  4. Copyright 1989, 1990, 1991 by Sun Microsystems, Inc. and the X Consortium.
  5.  
  6.                         All Rights Reserved
  7.  
  8. Permission to use, copy, modify, and distribute this software and its 
  9. documentation for any purpose and without fee is hereby granted, 
  10. provided that the above copyright notice appear in all copies and that
  11. both that copyright notice and this permission notice appear in 
  12. supporting documentation, and that the names of Sun Microsystems,
  13. the X Consortium, and MIT not be used in advertising or publicity 
  14. pertaining to distribution of the software without specific, written 
  15. prior permission.  
  16.  
  17. SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 
  18. INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT 
  19. SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL 
  20. DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  21. WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  22. ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  23. SOFTWARE.
  24.  
  25. ******************************************************************/
  26.  
  27. #include "phg.h"
  28. #include "cp.h"
  29. #include "cp_priv.h"
  30. #include "sin.h"
  31. #include <stdio.h>
  32. #include <errno.h>
  33. #include <sys/types.h>
  34. #ifndef PEX_API_SOCKET_IPC
  35. #include <sys/ipc.h>
  36. #include <sys/shm.h>
  37. #endif
  38. #include <sys/socket.h>
  39. #include <fcntl.h>
  40. #include <signal.h>
  41. #ifdef AIXV3
  42. #include <sys/ioctl.h>
  43. #endif
  44.  
  45. #define CPR_CMD_TIMEOUT        250000
  46.  
  47. #ifndef X_NOT_STDC_ENV
  48. #include <stdlib.h>
  49. #else
  50. extern char* getenv();
  51. #endif
  52.  
  53. /* The CP handle for this invocation. */
  54. static Cp_handle    phigs_cph;
  55.  
  56. /* Interval values are {interval, initial} */
  57. static struct itimerval    check_parent_interval = { 2, 0, 2, 0};
  58. static struct timeval    cmd_check_interval = { 0, 100 };
  59.  
  60. #ifndef PEX_API_SOCKET_IPC
  61. static int
  62. attach_shared_mem( cph )
  63.     Cp_handle    cph;
  64. {
  65.     /* Take pains not to leave shared memory segments lying around:
  66.      * The shared memory segment is "removed" by the parent after it
  67.      * attaches to it.  Once "removed," the segment will go away when all
  68.      * processes attached to it terminate.  Until then, processes attached
  69.      * to it can use it even though it's been "removed."  If not removed,
  70.      * it exists forever, even after all the processes using it die.
  71.      *
  72.      * The segment is created here because getting as far as this in the
  73.      * program indicates that successful startup is likely.  We want to
  74.      * create the segment when we know it's likely we can destroy it
  75.      * normally.  Otherwise it might be left around.
  76.      */
  77.  
  78.     int        shmid, status = 0;
  79.     extern int    errno;    /* kernel reports here why system call failed */
  80.  
  81.     shmid = shmget( IPC_PRIVATE, sizeof(Cp_shm_buf), 0666 );
  82.     if ( shmid < 0 ) {
  83.     switch (errno) {
  84.     case EINVAL:
  85.         ERR_BUF( cph->erh, ERRN57);
  86.         break;
  87.     case ENOSPC:
  88.         /* IPCSHMEM facility is configured into the kernel,
  89.          * but shared memory resources are exhaused.
  90.          * This error is unlikely, so a specific error message
  91.          * is overkill.
  92.          *
  93.          * The parent process will raise the error -1:
  94.          * "cannot create communication channel".
  95.          */
  96.         break;
  97.     default:
  98. #ifdef    DEBUG
  99.         fprintf(stderr, "PHIGSMON: errno is %d after shmget\n", errno);
  100. #endif    /* DEBUG */
  101.         ERR_BUF( cph->erh, ERRN50);
  102.         break;
  103.     }
  104.     } else {
  105.     extern int errno;    /* kernel reports here why system call failed */
  106.     assure(shmid >= 0)
  107.     cph->shm_buf = (Cp_shm_buf *)shmat( shmid, (char *)NULL, 0 );
  108.     if ( cph->shm_buf == (Cp_shm_buf *)-1 ) {
  109. #ifdef    DEBUG
  110.         fprintf(stderr, "PHIGSMON: errno is %d after shmat\n", errno);
  111. #endif    /* DEBUG */
  112.         /* Assign a more specific error number to this error,
  113.          * if it is ever observed.
  114.          */
  115.         ERR_BUF( cph->erh, ERRN50);
  116.         (void)shmctl( shmid, IPC_RMID, (struct shmid_ds *)NULL );
  117.         cph->shm_buf = (Cp_shm_buf *)NULL;
  118.     } else {
  119.         cph->shm_buf->shmid = shmid;
  120.         cph->shm_buf->args.lock = 0;
  121.         cph->shm_buf->args.head = 0;
  122.         cph->shm_buf->args.tail = 0;
  123.         cph->shm_buf->args.buf_size = CP_SHM_ARGS_BUF_SIZE;
  124.  
  125.         cph->shm_buf->data.lock = 0;
  126.         cph->shm_buf->data.head = 0;
  127.         cph->shm_buf->data.tail = 0;
  128.         cph->shm_buf->data.buf_size = sizeof(cph->shm_buf->data.buf);
  129.  
  130.         cph->shm_buf->ret.buf_size = sizeof(cph->shm_buf->ret.buf);
  131.         status = 1;
  132. #ifdef    DEBUG
  133.         CP_CHECK_SHM_LOCK(cph->shm_buf,args)
  134.         if (getenv("PHIGSMON_WAIT") != NULL)
  135.         fprintf(stderr, "PHIGSMON: shmid is %d; shm_buf is %#x\n",
  136.                     shmid, cph->shm_buf);
  137. #endif    /* DEBUG */
  138.     }
  139.     }
  140.  
  141.     return status;
  142. }
  143.  
  144.  
  145. #else /* PEX_API_SOCKET_IPC defined */
  146. static Cp_shm_buf    dummy_shm_buf;
  147.  
  148. static int
  149. dummy_attach( cph )
  150.     Cp_handle    cph;
  151. {
  152.     /* Shared memory not used, just attach a small fake buffer with control
  153.      * values set to force all data to go through the socket.
  154.      */
  155.     cph->shm_buf = &dummy_shm_buf;
  156.     cph->data.monitor.arg_buf = dummy_shm_buf.args.buf;
  157.     cph->data.monitor.ret_buf = &dummy_shm_buf.ret.data;
  158.     /* Zero buffer sizes force the data to be sent through the socket. */
  159.     cph->shm_buf->args.buf_size = 0;
  160.     cph->shm_buf->data.buf_size = 0;
  161.     cph->shm_buf->ret.buf_size = 0;
  162.     return 1;
  163. }
  164. #endif /* ! PEX_API_SOCKET_IPC */
  165.  
  166. static Cp_handle
  167. set_up( s, es)
  168.     int        s, es;
  169. {
  170.     register Cp_handle    cph = NULL, tcph;
  171.     Cpx_css_srvr    *css_srvr;
  172.  
  173.     /* Don't bother cleaning up on failure, the process will just exit. */
  174.     if ( tcph = (Cp_handle)calloc( 1, sizeof(Cp_struct))) {
  175.     tcph->configuration = CP_REMOTE;
  176.     if ( !(tcph->erh = phg_err_init_remote( es))) {
  177.         ;
  178.  
  179.     } else if ( !(tcph->data.monitor.infile = phg_cpr_fdopen( s))) {
  180.         ERR_BUF( tcph->erh, ERR900);
  181.  
  182.     } else if ( !(css_srvr = phg_cpb_pm_init( tcph )) ) {
  183.         ; /* Any errors will have been reported already. */
  184.  
  185.     } else if ( !(tcph->input_q = phg_sin_q_create( tcph->erh)) ) {
  186.         ;
  187.  
  188. #ifndef PEX_API_SOCKET_IPC
  189.     } else if ( !attach_shared_mem( tcph ) ) {
  190. #else
  191.     } else if ( !dummy_attach( tcph ) ) {
  192. #endif
  193.         ;
  194.  
  195.     } else {
  196.         tcph->scratch.buf = NULL;
  197.         tcph->scratch.size = 0;
  198.  
  199.         tcph->flags.in_monitor = 1;
  200.         tcph->data.monitor.sfd = s;
  201.         tcph->data.monitor.cmd_state = CP_READING_ARGS;
  202.         tcph->data.monitor.cur_cnt = 0;
  203.         tcph->data.monitor.parent_pid = -1;
  204.         tcph->data.monitor.cmd_timeout.it_value.tv_sec = 0;
  205.         tcph->data.monitor.cmd_timeout.it_value.tv_usec = CPR_CMD_TIMEOUT;
  206.         tcph->data.monitor.cmd_timeout.it_interval.tv_sec = 0;
  207.         tcph->data.monitor.cmd_timeout.it_interval.tv_usec =
  208.         CPR_CMD_TIMEOUT;
  209.  
  210. #ifdef AIXV3
  211.         /* 
  212.          * AIX has a different Non-blocking IO call
  213.          */    
  214.             {
  215.                 int fdflags = 1;
  216.                 ioctl (s, FIONBIO, &fdflags);
  217.             }
  218. #else /* AIXV3 */
  219.         /* ultrix reads hang on Unix sockets, hpux reads fail */
  220. #if defined(O_NONBLOCK) && (!defined(ultrix) && !defined(hpux))
  221.         (void)fcntl(s, F_SETFL, O_NONBLOCK);
  222. #else
  223. #ifdef FIOSNBIO
  224.         {
  225.         int fdflags = 1;
  226.         ioctl (s, FIOSNBIO, &fdflags);
  227.         }
  228. #else
  229.         (void)fcntl(s, F_SETFL, FNDELAY);
  230. #endif
  231. #endif
  232. #endif /* AIXV3 */
  233.         if ( getenv( "PEX_SI_API_SYNC" ) )
  234.         tcph->flags.err_sync = 1;
  235.  
  236.         phg_cpm_load_monitor_funcs( tcph );
  237.         phg_cpx_link_css_srvr( tcph, css_srvr );
  238.         cph = tcph;
  239.     }
  240.     }
  241.  
  242.     return cph;
  243. }
  244.  
  245.  
  246. static void
  247. check_parent( cphp, which )
  248. Cp_handle    *cphp;
  249. int        which;
  250. {
  251.     if ( kill( (*cphp)->data.monitor.parent_pid, 0) < 0 && errno == ESRCH) {
  252. #ifndef PEX_API_SOCKET_IPC
  253.     /* Make sure the shared  memory segment is removed.  This is only
  254.      * necessary when the parent dies before it removes the segment,
  255.      * but do it all the time since we can't catch that case and the
  256.      * extra call doesn't hurt anything.
  257.      */
  258.     (void)shmctl( (*cphp)->shm_buf->shmid, IPC_RMID,
  259.         (struct shmid_ds *)NULL );
  260. #endif
  261.     exit(1);
  262.     }
  263.     return;
  264. }
  265.  
  266.  
  267. static Cp_handle
  268. start_socketpair()
  269. {
  270.     char        msg = 'p';
  271.  
  272.     if ( (phigs_cph = set_up( fileno(stdin), fileno(stdout)))) {
  273.     phigs_cph->data.monitor.parent_pid = getppid();
  274.  
  275.     /* Let the parent know we started okay and send the shared mem id. */
  276.     send( phigs_cph->data.monitor.sfd, &msg, sizeof(msg), 0);
  277. #ifndef PEX_API_SOCKET_IPC
  278.     send( phigs_cph->data.monitor.sfd, (char *)&phigs_cph->shm_buf->shmid,
  279.         sizeof(phigs_cph->shm_buf->shmid), 0 );
  280. #endif
  281.  
  282.     /* Register miscellaneous notify procs. */
  283.     phg_register_timer_func((unsigned long)&phigs_cph, check_parent,
  284.         ITIMER_REAL,
  285.         (unsigned long)(check_parent_interval.it_interval.tv_sec
  286.         * 1000000 + check_parent_interval.it_interval.tv_usec));
  287.     } else {
  288.     msg = 'e';
  289.     send( fileno(stdin), &msg, sizeof(msg), 0);
  290.     exit(2);
  291.     }
  292.  
  293.     return phigs_cph;
  294. }
  295.  
  296.  
  297. #ifdef DIAGNOSTIC
  298. #define PRINT( _s, _w ) fprintf( stderr, "%s, window %d\n", _s, _w );
  299.  
  300. static void
  301. print_X_event( event )
  302.     XEvent    *event;
  303. {
  304.     fprintf( stderr, "event type %d\n", event->type );
  305.     switch ( event->type ) {
  306.     case MapNotify:
  307.         PRINT( "MapNotify", event->xmap.window );
  308.         break;
  309.     case ConfigureNotify:
  310.         PRINT( "ConfigureNotify", event->xconfigure.window );
  311.         break;
  312.     case ReparentNotify:
  313.         PRINT( "ReparentNotify", event->xreparent.window );
  314.         break;
  315.     case Expose:
  316.         PRINT( "Expose", event->xexpose.window );
  317.         break;
  318.     case MappingNotify:
  319.         PRINT( "MappingNotify", event->xmapping.window );
  320.         break;
  321.     }
  322. }
  323. #endif /* DIAGNOSTIC */
  324.  
  325. void
  326. phg_check_and_dispatch_event( cph )
  327.     Cp_handle    cph;
  328. {
  329.     XEvent    event;
  330.  
  331.     register Cp_display_connection    *dcon;
  332.     
  333.     CPX_FOR_ALL_DISPLAYS(cph, dcon) {
  334.     if ( dcon->display ) {
  335.         while ( XPending(dcon->display) ) {
  336.         XNextEvent( dcon->display, &event );
  337. #ifdef DIAGNOSTIC
  338.         print_X_event( &event );
  339. #endif /* DIAGNOSTIC */
  340.         XtDispatchEvent( &event );
  341.         phg_ntfy_dispatch_event( dcon->display, &event );
  342.         }
  343.     }
  344.     }
  345. }
  346.  
  347.  
  348. #ifdef DEBUG
  349.         int        phigsmon_wait = 1;
  350.     extern    int        cpr_print_trace;
  351.  
  352.  
  353. #define CP_SET_MALLOC_DEBUG_LEVEL \
  354.     { \
  355.     char    *debug_level; \
  356.     if ( debug_level = getenv("PHIGSMON_MALLOC_LEVEL") ) \
  357.         malloc_debug( atoi(debug_level) ); \
  358.     }
  359. #else
  360. #define CP_SET_MALLOC_DEBUG_LEVEL    {}
  361. #endif /* DEBUG */
  362.  
  363.  
  364. extern XtAppContext    phg_cpm_init_toolkit();
  365.  
  366. #ifdef DEBUG
  367. #define DEBUG_PHIGSMON_SOCKET_COMMAND "/tmp/phigs_command"
  368. #define DEBUG_PHIGSMON_SOCKET_ERROR "/tmp/phigs_error"
  369. #include <sys/un.h>
  370. #endif
  371.  
  372. main(argc, argv)
  373.     int        argc;
  374.     char    *argv[];
  375. {
  376.     Cp_handle        cph;
  377.     char        *env;
  378.     int            (*rcv_cmd)();
  379.     XtAppContext    app_con;
  380.     
  381.  
  382. #ifdef DEBUG
  383. #ifdef BSD44SOCKETS
  384. #define Make(rendezvous,addr) {\
  385.     struct sockaddr_un    un_addr; \
  386.  \
  387.     unlink (addr); \
  388.     strcpy (un_addr.sun_path, addr); \
  389.     un_addr.sun_len = strlen(un_addr.sun_path); \
  390.     un_addr.sun_family = AF_UNIX; \
  391.     rendezvous = socket (AF_UNIX, SOCK_STREAM, 0); \
  392.     if (bind (rendezvous, &un_addr, SUN_LEN(&un_addr)) == -1) \
  393.     { \
  394.         perror ("phigs debug bind"); \
  395.         abort (); \
  396.     } \
  397.     listen (rendezvous, 5); \
  398. }
  399. #else
  400. #define Make(rendezvous,addr) {\
  401.     struct sockaddr_un    un_addr; \
  402.  \
  403.     unlink (addr); \
  404.     strcpy (un_addr.sun_path, addr); \
  405.     un_addr.sun_family = AF_UNIX; \
  406.     rendezvous = socket (AF_UNIX, SOCK_STREAM, 0); \
  407.     if (bind (rendezvous, &un_addr, sizeof (short) + strlen (addr)) == -1) \
  408.     { \
  409.         perror ("phigs debug bind"); \
  410.         abort (); \
  411.     } \
  412.     listen (rendezvous, 5); \
  413. }
  414. #endif
  415.  
  416. #define Get(fd,rendezvous) { \
  417.     struct sockaddr_un    un_addr; \
  418.     int            addr_len; \
  419.     \
  420.     addr_len = sizeof (un_addr); \
  421.     fd = accept (rendezvous, &un_addr, &addr_len); \
  422.     if (fd == -1) {\
  423.         perror ("phigs debug accept"); \
  424.         abort (); \
  425.     }\
  426. }
  427.     {
  428.     int    r_command, s_command;
  429.     int    r_error, s_error;
  430.     int    pid;
  431.  
  432.     Make (r_command, DEBUG_PHIGSMON_SOCKET_COMMAND);
  433.     Make (r_error, DEBUG_PHIGSMON_SOCKET_ERROR);
  434.     Get (s_command, r_command);
  435.     Get (s_error, r_error);
  436.     pid = getpid ();
  437.     write (s_command, &pid, sizeof (pid));
  438.     if (dup2 (s_command, 0) < 0) {
  439.         perror ("phigs debug dup command");
  440.         abort ();
  441.     }
  442.     if (dup2 (s_error, 1) < 0) {
  443.         perror ("phigs debug dup error");
  444.         abort ();
  445.     }
  446.     }
  447. #endif
  448. #ifdef SUN_DEBUG
  449.     {
  450.     char    *trace_val;
  451.  
  452.     if ( (env = getenv("PHIGSMON_CMD_INTERVAL")) != NULL) {
  453.         cmd_check_interval.tv_usec = atoi(env);
  454.     }
  455.  
  456.     if ( (trace_val = (char*)getenv("PHIGSMON_CP_TRACE")) != NULL ) {
  457.         cpr_print_trace = atoi( trace_val );
  458.     }
  459.  
  460.     /* Wait for debugger to attach to child. */
  461.     if (getenv("PHIGSMON_WAIT") != NULL) {
  462.         while (phigsmon_wait)
  463.         /* Attach a debugger, and then
  464.            set phigsmon_wait=0
  465.          * to continue.
  466.          */
  467.         if (kill( getppid(), 0) < 0 && errno == ESRCH) {
  468.             fprintf(stderr,
  469.             "PHIGSMON_WAIT: parent (%d) of phigsmon %d died\n",
  470.             getppid(), getpid());
  471.             exit(3);
  472.         } else
  473.             CP_MICROSLEEP( 100 ); /* sleep(1) won't return on sun4 */
  474.     }
  475.     }
  476. #endif /* DEBUG */
  477.  
  478.     if ( !(app_con = phg_cpm_init_toolkit( argc, argv )) )
  479.     exit(4);
  480.  
  481.     /* Initialize everything and link to parent. */
  482.     cph = start_socketpair();
  483.     BITSET(cph->fd_masks, cph->data.monitor.sfd);
  484.     cph->max_fd = cph->data.monitor.sfd;
  485.     cph->data.monitor.app_con = app_con;
  486.     cph->data.monitor.name = argv[1];
  487.     cph->data.monitor.classname = argv[2];
  488.     cph->data.monitor.argc = argc - 2;
  489.     cph->data.monitor.argv = &argv[3];
  490.  
  491. #ifdef DEBUG
  492.     if ( (env = getenv("PHIGSMON_CMD_TIMEOUT")) != NULL) {
  493.     cph->data.monitor.cmd_timeout.it_value.tv_usec = atoi(env);
  494.     cph->data.monitor.cmd_timeout.it_interval.tv_usec = atoi(env);
  495.     }
  496. #endif
  497.  
  498. #ifndef PEX_API_SOCKET_IPC
  499.     rcv_cmd = phg_cpr_rcv_cmd_shm;
  500. #else
  501.     rcv_cmd = phg_cpr_rcv_cmd_socket;
  502. #endif
  503.     while (1) {
  504.     unsigned long    rmask[MSKCNT];
  505.  
  506.     check_parent( &cph, 0 );
  507.     phg_check_and_dispatch_event(cph);
  508.  
  509.     if ((*rcv_cmd)(cph) == 0) {        
  510.         /* No commands pending from client.  Check for events then
  511.          * sleep a while.
  512.          */
  513.         check_parent( &cph, 0 );
  514.         phg_check_and_dispatch_event(cph);
  515.  
  516.         /* Block until interesting input available. */
  517.         COPYBITS(cph->fd_masks,rmask);
  518. #ifndef PEX_API_SOCKET_IPC
  519.         /* Need to wake up frequently to check the shared memory queue
  520.          * for commands from the parent.
  521.          */
  522.         select( cph->max_fd+1, rmask, NULL, NULL, &cmd_check_interval );
  523. #else
  524.         select( cph->max_fd+1, rmask, NULL, NULL, NULL );
  525. #endif
  526.     }
  527.     }
  528. }
  529.