home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / mitsch75.zip / scheme-7_5_17-src.zip / scheme-7.5.17 / src / microcode / bchdrn.c < prev    next >
C/C++ Source or Header  |  2000-12-05  |  15KB  |  546 lines

  1. /* -*- C -*-
  2.  
  3. $Id: bchdrn.c,v 1.10 2000/12/05 21:23:42 cph Exp $
  4.  
  5. Copyright (c) 1991-2000 Massachusetts Institute of Technology
  6.  
  7. This program is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2 of the License, or (at
  10. your option) any later version.
  11.  
  12. This program is distributed in the hope that it will be useful, but
  13. WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15. General Public License for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with this program; if not, write to the Free Software
  19. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20. */
  21.  
  22. /* Drone program for overlapped I/O in bchscheme. */
  23.  
  24. #include "ux.h"
  25. #include "bchdrn.h"
  26. #if 0
  27. /* ux.h includes <setjmp.h> indirectly */
  28. #  include <setjmp.h>
  29. #endif
  30.  
  31. #define DEBUG
  32. /* #define DEBUG_1 */
  33. /* #define DEBUG_2 */
  34.  
  35. extern char * EXFUN (error_name, (int));
  36. extern int EXFUN (retrying_file_operation,
  37.           (ssize_t EXFUN ((*), (int, char *, int)),
  38.            int, char *, long, long, char *, char *, long *,
  39.            int EXFUN ((*), (char *, char *))));
  40.  
  41. #ifdef USE_SYSV_SHARED_MEMORY
  42.  
  43. static struct
  44. {
  45.   char * program_name;
  46.   char * file_name;        /* gc file name */
  47.   int shmid;            /* shared memory descriptor */
  48.   int tdron;            /* total number of drones */
  49.   int nbuf;            /* total number of buffers */
  50.   long bufsiz;            /* size of each buffer in bytes */
  51.   int sdron;            /* index of first drone to start */
  52.   int ndron;            /* number of drones to start */
  53.   int keep_p;            /* keep the gc file if Scheme dies? */
  54. } arguments;
  55.  
  56. struct argdesc
  57. {
  58.   char * name;
  59.   char * format;
  60.   PTR location;
  61. };
  62.  
  63. static char string_a[] = "%s";
  64. #define STRING_FMT &string_a[0]
  65.  
  66. static char decimal_int_a[] = "%d";
  67. #define DECIMAL_INT_FMT &decimal_int_a[0]
  68.  
  69. static char decimal_long_a[] = "%ld";
  70. #define DECIMAL_LONG_FMT &decimal_long_a[0]
  71.  
  72. static struct argdesc command_line[] =
  73. {
  74.   { "program_name",    STRING_FMT,        &arguments.program_name },
  75.   { "file_name",    STRING_FMT,        &arguments.file_name },
  76.   { "shmid",        DECIMAL_INT_FMT,    &arguments.shmid },
  77.   { "tdron",        DECIMAL_INT_FMT,    &arguments.tdron },
  78.   { "nbuf",        DECIMAL_INT_FMT,    &arguments.nbuf },
  79.   { "bufsiz",        DECIMAL_LONG_FMT,    &arguments.bufsiz },
  80.   { "sdron",        DECIMAL_INT_FMT,    &arguments.sdron },
  81.   { "ndron",        DECIMAL_INT_FMT,    &arguments.ndron },
  82.   { "keep_gc_file",    DECIMAL_INT_FMT,    &arguments.keep_p }
  83. };
  84.  
  85. static int gc_fid = -1;
  86. static char * shared_memory;
  87. static struct buffer_info * gc_buffers;
  88. static struct drone_info * myself;
  89. static unsigned long * drone_version, * wait_mask;
  90. static jmp_buf abort_point;
  91. static pid_t boss_pid;
  92.  
  93. static void EXFUN (kill_program, (int sig));
  94.  
  95. static void 
  96. DEFUN (posix_signal, (signum, handler),
  97.        int signum AND void EXFUN ((*handler), ()))
  98. {
  99.   struct sigaction new;
  100.  
  101.   new.sa_handler = handler;
  102.   UX_sigemptyset (&new.sa_mask);
  103.   UX_sigaddset ((&new.sa_mask), SIGCONT);
  104.   UX_sigaddset ((&new.sa_mask), SIGQUIT);
  105.   new.sa_flags = SA_NOCLDSTOP;
  106.   
  107.   if ((UX_sigaction (signum, &new, 0)) == -1)
  108.   {
  109.     fprintf (stderr, "%s (%d, posix_signal): sigaction failed. errno = %s.\n",
  110.          arguments.program_name, myself->index, (error_name (errno)));
  111.     fflush (stderr);
  112.     kill_program (0);
  113.     /*NOTREACHED*/
  114.   }
  115.   return;
  116. }
  117.  
  118. static void
  119. DEFUN (kill_program, (sig), int sig)
  120. {
  121.   myself->state = drone_dead;
  122.   if (gc_fid != -1)
  123.     close (gc_fid);
  124.   shmdt (shared_memory);
  125.   if (sig == -1)
  126.   {
  127.     shmctl (arguments.shmid, IPC_RMID, ((struct shmid_ds *) 0));
  128.     if (!arguments.keep_p)
  129.       unlink (arguments.file_name);
  130.   }
  131.   exit (0);
  132.   /*NOTREACHED*/
  133. }
  134.  
  135. static void
  136. DEFUN (abort_operation, (sig), int sig)
  137. {
  138.   RE_INSTALL_HANDLER (SIGQUIT, abort_operation);
  139.   myself->state = drone_aborting;
  140.   longjmp (abort_point, 1);
  141.   /*NOTREACHED*/
  142. }
  143.  
  144. static void
  145. DEFUN (continue_running, (sig), int sig)
  146. {
  147.   RE_INSTALL_HANDLER (SIGCONT, continue_running);
  148.   longjmp (abort_point, 1);
  149.   /*NOTREACHED*/
  150. }
  151.  
  152. static int
  153. DEFUN (always_one, (operation_name, noise),
  154.        char * operation_name AND char * noise)
  155. {
  156.   return (1);
  157. }
  158.  
  159. static void
  160. DEFUN (process_requests, (drone), struct drone_info * drone)
  161. {
  162.   sigset_t non_blocking_signal_mask, blocking_signal_mask;
  163.   int result, count, buffer_index, flags;
  164.   long current_position = -1;
  165.   struct timeval timeout;
  166.   struct stat file_info;
  167.   unsigned long read_mask, my_mask;
  168.  
  169.   myself = drone;
  170.   my_mask = (((unsigned long) 1) << drone->index);
  171.   drone->DRONE_PID = (getpid ());
  172.   gc_fid = (open (arguments.file_name, O_RDWR, 0644));
  173.   if (gc_fid == -1)
  174.   {
  175.     fprintf (stderr,
  176.          "%s (%d, process_requests): open failed. errno = %s.\n",    
  177.          arguments.program_name, drone->index, (error_name (errno)));
  178.     fflush (stderr);
  179.     if (drone->DRONE_PPID == boss_pid)
  180.       (void) (kill (boss_pid, SIGCONT));
  181.     kill_program (0);
  182.     /*NOTREACHED*/
  183.   }
  184. #ifdef DEBUG_1
  185.   printf ("%s (%d, process_requests): Starting (pid = %d, ppid = %d).\n",
  186.       arguments.program_name, drone->index,
  187.       drone->DRONE_PID, drone->DRONE_PPID);
  188.   fflush (stdout);
  189. #endif
  190.   if ((result = (fstat (gc_fid, &file_info))) == -1)
  191.   {
  192.     fprintf (stderr,
  193.          "%s (%d, process_requests): fstat failed. errno = %s.\n",
  194.          arguments.program_name, drone->index, (error_name (errno)));
  195.     fflush (stderr);
  196.   }
  197.   /* Force O_SYNC only if we are dealing with a raw device. */
  198.     
  199.   if ((result == -1) || ((file_info.st_mode & S_IFMT) == S_IFCHR))
  200.   {
  201.     if ((flags = (fcntl (gc_fid, F_GETFL, 0))) == -1)
  202.     {
  203.       fprintf
  204.     (stderr,
  205.      "%s (%d, process_requests): fcntl (F_GETFL) failed. errno = %s.\n",
  206.      arguments.program_name, drone->index, (error_name (errno)));
  207.       fflush (stderr);
  208.     }
  209.     else
  210.     {
  211.       flags |= O_SYNC;
  212.       if ((fcntl (gc_fid, F_SETFL, flags)) == -1)
  213.       {
  214.     fprintf
  215.       (stderr,
  216.        "%s (%d, process_requests): fcntl (F_SETFL) failed. errno = %s.\n",
  217.        arguments.program_name, drone->index, (error_name (errno)));
  218.     fflush (stderr);
  219.       }
  220.     }
  221.   }
  222.  
  223.   UX_sigemptyset (&non_blocking_signal_mask);
  224.   UX_sigemptyset (&blocking_signal_mask);
  225.   UX_sigaddset ((&blocking_signal_mask), SIGCONT);
  226.   UX_sigaddset ((&blocking_signal_mask), SIGQUIT);
  227.   UX_sigprocmask (SIG_SETMASK, (&blocking_signal_mask), 0);
  228.   posix_signal (SIGQUIT, abort_operation);
  229.   posix_signal (SIGCONT, continue_running);
  230.  
  231.   if ((setjmp (abort_point)) == 0)
  232.   {
  233.     count = drone->index; 
  234.     drone->state = drone_idle;
  235.     if (drone->DRONE_PPID == boss_pid)
  236.       (void) (kill (boss_pid, SIGCONT));
  237.   }
  238.   else
  239.     goto redo_dispatch;
  240.  
  241.   for (; 1; count++)
  242.   {
  243.     timeout.tv_sec = 6;
  244.     timeout.tv_usec = 0;
  245.  
  246.     UX_sigprocmask (SIG_SETMASK, (&non_blocking_signal_mask), 0);
  247.     result = (select (0, 0, 0, 0, &timeout));
  248.     UX_sigprocmask (SIG_SETMASK, (&blocking_signal_mask), 0);
  249.  
  250.     if ((drone->state != drone_idle)
  251.     || ((result == -1) && (errno == EINTR)))
  252.     {
  253.       if (result != -1)
  254.       {
  255.     fprintf (stderr,
  256.          "\n%s (%d, process_requests): request after timeout %d.\n",
  257.          arguments.program_name, drone->index, drone->state);
  258.     fflush (stderr);
  259.       }
  260. redo_dispatch:
  261.       switch (drone->state)
  262.       {
  263.     default:
  264.       fprintf (stderr,
  265.            "\n%s (%d, process_requests): Unknown/bad operation %d.\n",
  266.            arguments.program_name, drone->index, drone->state);
  267.       fflush (stderr);
  268.       kill_program (0);
  269.       /*NOTREACHED*/
  270.  
  271.     case drone_idle:
  272.       break;
  273.  
  274.     case drone_aborting:
  275. #ifdef DEBUG_1
  276.       printf ("\n%s (%d, process_requests): Aborting.",
  277.           arguments.program_name, drone->index);
  278.       fflush (stdout);
  279. #endif
  280.       drone->buffer_index = -1;
  281.       current_position = -1;
  282.       break;
  283.  
  284.     case drone_reading:
  285.     case drone_writing:
  286.     {
  287.       /* Can't use buffer->bottom because the shared memory may be
  288.          attached at a different address!
  289.        */
  290.  
  291.       int saved_errno;
  292.       enum drone_state operation;
  293.       char * operation_name, * buffer_address;
  294.       struct buffer_info * buffer;
  295.       struct gc_queue_entry * entry;
  296.  
  297.       operation = drone->state;
  298.       buffer_index = (drone->buffer_index);
  299.       buffer = (gc_buffers + buffer_index);
  300.  
  301.       entry = ((struct gc_queue_entry *)
  302.            (((char *) drone) + (drone->entry_offset)));
  303.       entry->error_code = 0;
  304.  
  305.       operation_name = ((operation == drone_reading) ? "read" : "write");
  306.       buffer_address = (shared_memory + (arguments.bufsiz * buffer_index));
  307. #ifdef DEBUG_1
  308.       printf ("\n%s (%d, process_requests %s): Buffer index = %d.\n",
  309.           arguments.program_name, drone->index, operation_name,
  310.           buffer_index);
  311.       printf ("\tBuffer address = 0x%lx; Position = 0x%lx; Size = 0x%lx.",
  312.           buffer_address, buffer->position, buffer->size);
  313.       fflush (stdout);
  314. #endif
  315.  
  316.       UX_sigprocmask (SIG_SETMASK, (&non_blocking_signal_mask), 0);
  317.       result = (retrying_file_operation
  318.             (((operation == drone_reading) ? read : write),
  319.              gc_fid, buffer_address,
  320.              buffer->position, buffer->size, operation_name, NULL,
  321.              ¤t_position, always_one));
  322.       saved_errno = errno;
  323.       UX_sigprocmask (SIG_SETMASK, (&blocking_signal_mask), 0);
  324.  
  325.       if (result == -1)
  326.       {
  327.         buffer->state = ((operation == drone_reading)
  328.                  ? buffer_read_error
  329.                  : buffer_write_error);
  330.         drone->buffer_index = -1;
  331.         entry->drone_index = -1;
  332.         entry->error_code = saved_errno;
  333.         entry->state = entry_error;
  334.         current_position = -1;
  335. #ifdef DEBUG
  336.         printf ("\n%s (%d, process_requests): %s error (errno = %s).\n",
  337.             arguments.program_name, drone->index, operation_name,
  338.             (error_name (saved_errno)));
  339.         fflush (stdout);
  340. #endif
  341.       }
  342.  
  343.       else
  344.       {
  345.         buffer->state = ((operation == drone_reading)
  346.                  ? buffer_ready
  347.                  : buffer_idle);
  348.         drone->buffer_index = -1;
  349.         entry->drone_index = -1;
  350.         if (operation == drone_writing)
  351.         {
  352.           entry->retry_count = 0;
  353.           entry->state = entry_idle;
  354.         }
  355.  
  356. #ifdef DEBUG_1
  357.       printf ("\n%s (%d, process_requests %s): Done.",
  358.           arguments.program_name, drone->index, operation_name);
  359.       fflush (stdout);
  360. #endif
  361.       }
  362.     }
  363.       }
  364.  
  365.       count = 0;
  366.       drone->state = drone_idle;
  367.       read_mask = (* wait_mask);
  368.       if ((read_mask & my_mask) == my_mask)
  369.     (void) (kill (boss_pid, SIGCONT));
  370.     }
  371.     else if (result == 0)
  372.     {
  373.       if (count == arguments.tdron)
  374.       {
  375.     count = 0;
  376.     if ((kill (boss_pid, 0)) == -1)
  377.       kill_program (-1);
  378.       }
  379.       read_mask = (* wait_mask);
  380.       if ((read_mask & my_mask) == my_mask)
  381.       {
  382.     fprintf (stderr,
  383.          "\n%s (%d, process_requests): signal deadlock (%s)!\n",
  384.          arguments.program_name, drone->index,
  385.          ((read_mask == ((unsigned long) -1)) ? "any" : "me"));
  386.     fflush (stderr);
  387.     drone->state = drone_idle; /* !! */
  388.     (void) (kill (boss_pid, SIGCONT));
  389.       }
  390.     }
  391.   }
  392. }
  393.  
  394. static void
  395. DEFUN_VOID (start_drones)
  396. {
  397.   pid_t my_pid;
  398.   int counter, cpid;
  399.   struct drone_info *gc_drones, *drone;
  400.  
  401.   my_pid = (getpid ());
  402.  
  403.   shared_memory = (shmat (arguments.shmid, ((char *) 0), 0));
  404.   if (shared_memory == ((char *) -1))
  405.   {
  406.     fprintf (stderr,
  407.          "\
  408. %s (start_drones): Unable to attach shared memory segment %d (errno = %s).\n",
  409.          arguments.program_name, arguments.shmid, (error_name (errno)));
  410.     fflush (stderr);
  411.     sleep (10);
  412.     kill (boss_pid, SIGCONT);
  413.     exit (1);
  414.   }
  415. #ifdef DEBUG_1
  416.   printf ("%s (start_drones): Attached shared memory at address = 0x%lx.\n",
  417.       arguments.program_name, ((long) shared_memory));
  418.   fflush (stdout);
  419. #endif
  420.   posix_signal (SIGINT, SIG_IGN);
  421.   posix_signal (SIGQUIT, SIG_IGN);
  422.   posix_signal (SIGHUP, kill_program);
  423.   posix_signal (SIGTERM, kill_program);
  424.  
  425.   gc_buffers = ((struct buffer_info *)
  426.         (shared_memory + (arguments.nbuf * arguments.bufsiz)));
  427.   gc_drones = ((struct drone_info *) (gc_buffers + arguments.nbuf));
  428.   drone_version = ((unsigned long *) (gc_drones + arguments.tdron));
  429.   wait_mask = (drone_version + 1);
  430.   if ((* drone_version) != ((unsigned long) DRONE_VERSION_NUMBER))
  431.   {
  432.     fprintf (stderr,
  433.          "%s (start_drones): stored drone version != drone version.\n",
  434.          arguments.program_name);
  435.     fprintf (stderr, "\t*drone_version = %ld; DRONE_VERSION_NUMBER = %ld.\n",
  436.          (* drone_version), ((unsigned long) DRONE_VERSION_NUMBER));
  437.     fflush (stderr);
  438.     kill (boss_pid, SIGCONT);
  439.     exit (1);
  440.   }
  441.  
  442.   for (counter = 1, drone = (gc_drones + (arguments.sdron + 1));
  443.        counter < arguments.ndron;
  444.        counter++, drone ++)
  445.   {
  446.     if ((cpid = (fork ())) == 0)
  447.     {
  448.       drone->DRONE_PPID = my_pid;
  449.       process_requests (drone);
  450.       /*NOTREACHED*/
  451.     }
  452.     else if (cpid == -1)
  453.     {
  454.       fprintf (stderr,
  455.            "%s (start_drones): fork failed; errno = %s.\n",
  456.            arguments.program_name, (error_name (errno)));
  457.       fflush (stderr);
  458.     }
  459.   }
  460.   drone = (gc_drones + arguments.sdron);
  461.   drone->DRONE_PPID = boss_pid;
  462.   /* This is non-portable behavior to prevent zombies from being created. */
  463.   if (arguments.ndron != 1)
  464.     posix_signal (SIGCHLD, SIG_IGN);
  465.   process_requests (drone);
  466.   /*NOTREACHED*/
  467. }
  468.  
  469. int
  470. DEFUN (main, (argc, argv), int argc AND char ** argv)
  471. {
  472.   int count, nargs;
  473.   static char err_buf[1024];
  474. #if defined(DEBUG) || defined(DEBUG_1) || defined(DEBUG_2)
  475.   static char out_buf[1024];
  476.  
  477.   setvbuf (stdout, &out_buf[0], _IOFBF, (sizeof (out_buf)));
  478. #endif
  479.   setvbuf (stderr, &err_buf[0], _IOFBF, (sizeof (err_buf)));
  480.  
  481. #ifdef DEBUG_2
  482.   printf ("%s (main): Arguments =\n", argv[0]);
  483.   for (count = 1; count < argc; count++)
  484.     printf ("\t%s\n", argv[count]);
  485.   fflush (stdout);
  486. #endif
  487.  
  488.   nargs = ((sizeof (command_line)) / (sizeof (struct argdesc)));
  489.   boss_pid = (getppid ());
  490.   if (argc != nargs)
  491.   {
  492.     fprintf (stderr,
  493.          "%s (main): Wrong number of arguments (got %d, expected %d).\n",
  494.          argv[0], (argc - 1), (nargs - 1));
  495.     fflush (stderr);
  496.     kill (boss_pid, SIGCONT);
  497.     exit (1);
  498.   }
  499.   for (count = 0; count < nargs; count++)
  500.   {
  501.     if (command_line[count].format == STRING_FMT)
  502.       (* ((char **) command_line[count].location)) = argv[count];
  503.     else
  504.       sscanf (argv[count],
  505.           command_line[count].format,
  506.           command_line[count].location);
  507.   }
  508.  
  509. #ifdef DEBUG_2
  510.   printf ("%s (main): Parsed arguments =\n", argv[0]);
  511.   for (count = 0; count < nargs; count++)
  512.   {
  513.     if (command_line[count].format == STRING_FMT)
  514.       printf ("\t%s\t= %s\n",
  515.           command_line[count].name,
  516.           (* ((char **) (command_line[count].location))));
  517.     else
  518.       printf ("\t%s\t= %d\n",
  519.           command_line[count].name,
  520.           (* ((int *) (command_line[count].location))));
  521.   }
  522.   fflush (stdout);
  523. #endif
  524.  
  525.   start_drones ();
  526.   /*NOTREACHED*/
  527.   return (0);
  528. }
  529.  
  530. #define MAIN main
  531.  
  532. #endif /* USE_SYSV_SHARED_MEMORY */
  533.  
  534. #ifndef MAIN
  535.  
  536. int
  537. DEFUN (main, (argc, argv), int argc AND char ** argv)
  538. {
  539.   fprintf (stderr, "%s: Not implemented.\n", (argv[0]));
  540.   fflush (stderr);
  541.   exit (1);
  542.   return (1);
  543. }
  544.  
  545. #endif /* MAIN */
  546.