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 / uxproc.c < prev    next >
C/C++ Source or Header  |  2001-05-03  |  22KB  |  794 lines

  1. /* -*-C-*-
  2.  
  3. $Id: uxproc.c,v 1.27 2001/05/03 20:14:51 cph Exp $
  4.  
  5. Copyright (c) 1990-2001 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  20. USA.
  21. */
  22.  
  23. #include "ux.h"
  24. #include "uxproc.h"
  25. #include "uxio.h"
  26. #include "osterm.h"
  27. #include "ostop.h"
  28.  
  29. #ifndef HAVE_DUP2
  30. #include "error: can't hack subprocess I/O without dup2() or equivalent"
  31. #endif
  32.  
  33. extern void EXFUN ((*subprocess_death_hook), (pid_t pid, int * status));
  34. extern void EXFUN ((*stop_signal_hook), (int signo));
  35. extern void EXFUN (stop_signal_default, (int signo));
  36. extern int EXFUN (OS_ctty_fd, (void));
  37. extern void EXFUN (UX_initialize_child_signals, (void));
  38.  
  39. static void EXFUN (subprocess_death, (pid_t pid, int * status));
  40. static void EXFUN (stop_signal_handler, (int signo));
  41. static void EXFUN (give_terminal_to, (Tprocess process));
  42. static void EXFUN (get_terminal_back, (void));
  43. static void EXFUN (process_wait, (Tprocess process));
  44. static int EXFUN (child_setup_tty, (int fd));
  45.  
  46. size_t OS_process_table_size;
  47. struct process * process_table;
  48. enum process_jc_status scheme_jc_status;
  49.  
  50. static int scheme_ctty_fd;
  51. static Tprocess foreground_child_process;
  52.  
  53. static long process_tick;
  54. static long sync_tick;
  55.  
  56. #define NEW_RAW_STATUS(process, status, reason)                \
  57. {                                    \
  58.   (PROCESS_RAW_STATUS (process)) = (status);                \
  59.   (PROCESS_RAW_REASON (process)) = (reason);                \
  60.   (PROCESS_TICK (process)) = (++process_tick);                \
  61. }
  62.  
  63. #define PROCESS_STATUS_SYNC(process)                    \
  64. {                                    \
  65.   (PROCESS_STATUS (process)) = (PROCESS_RAW_STATUS (process));        \
  66.   (PROCESS_REASON (process)) = (PROCESS_RAW_REASON (process));        \
  67.   (PROCESS_SYNC_TICK (process)) = (PROCESS_TICK (process));        \
  68. }
  69.  
  70. /* This macro should only be used when
  71.    (scheme_jc_status == process_jc_status_jc). */
  72. #define SCHEME_IN_FOREGROUND()                        \
  73.   ((UX_tcgetpgrp (scheme_ctty_fd)) == (UX_getpgrp ()))
  74.  
  75. #ifdef HAVE_POSIX_SIGNALS
  76.  
  77. static void
  78. DEFUN (restore_signal_mask, (environment), PTR environment)
  79. {
  80.   UX_sigprocmask (SIG_SETMASK, ((sigset_t *) environment), 0);
  81. }
  82.  
  83. static void
  84. DEFUN_VOID (block_sigchld)
  85. {
  86.   sigset_t * outside = (dstack_alloc (sizeof (sigset_t)));
  87.   sigset_t sigchld;
  88.   UX_sigemptyset (&sigchld);
  89.   UX_sigaddset ((&sigchld), SIGCHLD);
  90.   UX_sigprocmask (SIG_BLOCK, (&sigchld), outside);
  91.   transaction_record_action (tat_always, restore_signal_mask, outside);
  92. }
  93.  
  94. static void
  95. DEFUN_VOID (block_jc_signals)
  96. {
  97.   sigset_t * outside = (dstack_alloc (sizeof (sigset_t)));
  98.   sigset_t jc_signals;
  99.   UX_sigemptyset (&jc_signals);
  100.   UX_sigaddset ((&jc_signals), SIGCHLD);
  101.   UX_sigaddset ((&jc_signals), SIGTTOU);
  102.   UX_sigaddset ((&jc_signals), SIGTTIN);
  103.   UX_sigaddset ((&jc_signals), SIGTSTP);
  104.   UX_sigaddset ((&jc_signals), SIGSTOP);
  105.   UX_sigprocmask (SIG_BLOCK, (&jc_signals), outside);
  106.   transaction_record_action (tat_always, restore_signal_mask, outside);
  107. }
  108.  
  109. static sigset_t grabbed_signal_mask;
  110.  
  111. static void
  112. DEFUN_VOID (grab_signal_mask)
  113. {
  114.   UX_sigprocmask (SIG_BLOCK, 0, (&grabbed_signal_mask));
  115. }
  116.  
  117. #else /* not HAVE_POSIX_SIGNALS */
  118.  
  119. #ifdef HAVE_SIGHOLD
  120.  
  121. static void
  122. DEFUN (release_sigchld, (environment), PTR environment)
  123. {
  124.   UX_sigrelse (SIGCHLD);
  125. }
  126.  
  127. static void
  128. DEFUN_VOID (block_sigchld)
  129. {
  130.   UX_sighold (SIGCHLD);
  131.   transaction_record_action (tat_always, release_sigchld, 0);
  132. }
  133.  
  134. #else /* not HAVE_SIGHOLD */
  135.  
  136. #define block_sigchld()
  137.  
  138. #endif /* not HAVE_SIGHOLD */
  139.  
  140. #define block_jc_signals block_sigchld
  141. #define grab_signal_mask()
  142.  
  143. #endif /* not HAVE_POSIX_SIGNALS */
  144.  
  145. void
  146. DEFUN_VOID (UX_initialize_processes)
  147. {
  148.   OS_process_table_size = (UX_SC_CHILD_MAX ());
  149.   process_table =
  150.     (UX_malloc (OS_process_table_size * (sizeof (struct process))));
  151.   if (process_table == 0)
  152.     {
  153.       fprintf (stderr, "\nUnable to allocate process table.\n");
  154.       fflush (stderr);
  155.       termination_init_error ();
  156.     }
  157.   {
  158.     Tprocess process;
  159.     for (process = 0; (process < OS_process_table_size); process += 1)
  160.       OS_process_deallocate (process);
  161.   }
  162.   scheme_ctty_fd = (OS_ctty_fd ());
  163.   scheme_jc_status =
  164.     ((scheme_ctty_fd < 0)
  165.      ? process_jc_status_no_ctty
  166.      : (UX_SC_JOB_CONTROL ())
  167.      ? process_jc_status_jc
  168.      : process_jc_status_no_jc);
  169.   foreground_child_process = NO_PROCESS;
  170.   subprocess_death_hook = subprocess_death;
  171.   stop_signal_hook = stop_signal_handler;
  172.   process_tick = 0;
  173.   sync_tick = 0;
  174. }
  175.  
  176. void
  177. DEFUN_VOID (UX_reset_processes)
  178. {
  179.   UX_free (process_table);
  180.   process_table = 0;
  181.   OS_process_table_size = 0;
  182. }
  183.  
  184. static void
  185. DEFUN (process_allocate_abort, (environment), PTR environment)
  186. {
  187.   Tprocess process = (* ((Tprocess *) environment));
  188.   switch (PROCESS_RAW_STATUS (process))
  189.     {
  190.     case process_status_stopped:
  191.     case process_status_running:
  192.       UX_kill ((PROCESS_ID (process)), SIGKILL);
  193.       break;
  194.     default:
  195.       break;
  196.     }
  197.   OS_process_deallocate (process);
  198. }
  199.  
  200. static Tprocess
  201. DEFUN_VOID (process_allocate)
  202. {
  203.   Tprocess process;
  204.   for (process = 0; (process < OS_process_table_size); process += 1)
  205.     if ((PROCESS_RAW_STATUS (process)) == process_status_free)
  206.       {
  207.     Tprocess * pp = (dstack_alloc (sizeof (Tprocess)));
  208.     (*pp) = process;
  209.     transaction_record_action (tat_abort, process_allocate_abort, pp);
  210.     (PROCESS_RAW_STATUS (process)) = process_status_allocated;
  211.     return (process);
  212.       }
  213.   error_out_of_processes ();
  214.   return (NO_PROCESS);
  215. }
  216.  
  217. void
  218. DEFUN (OS_process_deallocate, (process), Tprocess process)
  219. {
  220.   (PROCESS_ID (process)) = 0;
  221.   (PROCESS_RAW_STATUS (process)) = process_status_free;
  222. }
  223.  
  224. Tprocess
  225. DEFUN (OS_make_subprocess,
  226.        (filename, argv, envp, working_directory,
  227.     ctty_type, ctty_name,
  228.     channel_in_type, channel_in,
  229.     channel_out_type, channel_out,
  230.     channel_err_type, channel_err),
  231.        CONST char * filename AND
  232.        CONST char ** argv AND
  233.        CONST char ** VOLATILE envp AND
  234.        CONST char * working_directory AND
  235.        enum process_ctty_type ctty_type AND
  236.        char * ctty_name AND
  237.        enum process_channel_type channel_in_type AND
  238.        Tchannel channel_in AND
  239.        enum process_channel_type channel_out_type AND
  240.        Tchannel channel_out AND
  241.        enum process_channel_type channel_err_type AND
  242.        Tchannel channel_err)
  243. {
  244.   pid_t child_pid;
  245.   Tprocess child;
  246.   VOLATILE enum process_jc_status child_jc_status = process_jc_status_no_ctty;
  247.  
  248.   if (envp == 0)
  249.     envp = ((CONST char **) environ);
  250.   switch (ctty_type)
  251.     {
  252.     case process_ctty_type_none:
  253.       child_jc_status = process_jc_status_no_ctty;
  254.       break;
  255.     case process_ctty_type_explicit:
  256.       child_jc_status = process_jc_status_unrelated;
  257.       break;
  258.     case process_ctty_type_inherit_bg:
  259.     case process_ctty_type_inherit_fg:
  260.       child_jc_status = scheme_jc_status;
  261.       break;
  262.     }
  263.  
  264.   transaction_begin ();
  265.   child = (process_allocate ());
  266.  
  267.   /* Flush streams so that output won't be duplicated after the fork.  */
  268.   fflush (stdout);
  269.   fflush (stderr);
  270.  
  271.   grab_signal_mask ();
  272.   if (ctty_type == process_ctty_type_inherit_fg)
  273.     block_jc_signals ();
  274.   else
  275.     block_sigchld ();
  276.   STD_UINT_SYSTEM_CALL (syscall_vfork, child_pid, (UX_vfork ()));
  277.   if (child_pid > 0)
  278.     {
  279.       /* In the parent process. */
  280.       (PROCESS_ID (child)) = child_pid;
  281.       (PROCESS_JC_STATUS (child)) = child_jc_status;
  282.       (PROCESS_RAW_STATUS (child)) = process_status_running;
  283.       (PROCESS_RAW_REASON (child)) = 0;
  284.       (PROCESS_TICK (child)) = process_tick;
  285.       PROCESS_STATUS_SYNC (child);
  286.       if (child_jc_status == process_jc_status_jc)
  287.     STD_VOID_SYSTEM_CALL
  288.       (syscall_setpgid, (UX_setpgid (child_pid, child_pid)));
  289.       if (ctty_type == process_ctty_type_inherit_fg)
  290.     {
  291.       give_terminal_to (child);
  292.       process_wait (child);
  293.     }
  294.       transaction_commit ();
  295.       return (child);
  296.     }
  297.  
  298.   /* In the child process -- if any errors occur, just exit. */
  299.   child_pid = (UX_getpid ());
  300.   /* Don't do `transaction_commit ()' here.  Because we used `vfork'
  301.      to spawn the child, the side-effects that are performed by
  302.      `transaction_commit' will occur in the parent as well. */
  303.   if (working_directory != 0)
  304.     UX_chdir (working_directory);
  305.   {
  306.     int in_fd = (-1);
  307.     int out_fd = (-1);
  308.     int err_fd = (-1);
  309.  
  310.     if (channel_in_type == process_channel_type_explicit)
  311.       in_fd = (CHANNEL_DESCRIPTOR (channel_in));
  312.     if (channel_out_type == process_channel_type_explicit)
  313.       out_fd = (CHANNEL_DESCRIPTOR (channel_out));
  314.     if (channel_err_type == process_channel_type_explicit)
  315.       err_fd = (CHANNEL_DESCRIPTOR (channel_err));
  316.  
  317.     if ((ctty_type == process_ctty_type_inherit_bg)
  318.     || (ctty_type == process_ctty_type_inherit_fg))
  319.       {
  320.     /* If the control terminal is inherited and job control is
  321.        available, force the child into a different process group. */
  322.     if (child_jc_status == process_jc_status_jc)
  323.       {
  324.         if (((UX_setpgid (child_pid, child_pid)) < 0)
  325.         || ((ctty_type == process_ctty_type_inherit_fg)
  326.             && (SCHEME_IN_FOREGROUND ())
  327.             && ((UX_tcsetpgrp (scheme_ctty_fd, child_pid)) < 0)))
  328.           goto kill_child;
  329.       }
  330.       }
  331.     else
  332.       {
  333.     /* If the control terminal is not inherited, force the child
  334.        into a different session. */
  335.     if ((UX_setsid ()) < 0)
  336.       goto kill_child;
  337.     /* If the control terminal is explicit, open the given device
  338.        now so it becomes the control terminal. */
  339.     if (ctty_type == process_ctty_type_explicit)
  340.       {
  341.         int fd = (UX_open (ctty_name, O_RDWR, 0));
  342.         if ((fd < 0)
  343. #ifdef SLAVE_PTY_P
  344.         || ((SLAVE_PTY_P (ctty_name)) && (!UX_setup_slave_pty (fd)))
  345. #endif
  346.         || (!isatty (fd))
  347. #ifdef TIOCSCTTY
  348.         || ((UX_ioctl (fd, TIOCSCTTY, 0)) < 0)
  349. #endif
  350.         /* Tell the controlling terminal its process group. */
  351.         || (((UX_tcsetpgrp (fd, child_pid)) < 0) && (errno != ENOSYS))
  352.         || ((child_setup_tty (fd)) < 0))
  353.           goto kill_child;
  354.         /* Use CTTY for standard I/O if requested. */
  355.         if (channel_in_type == process_channel_type_ctty)
  356.           in_fd = fd;
  357.         if (channel_out_type == process_channel_type_ctty)
  358.           out_fd = fd;
  359.         if (channel_err_type == process_channel_type_ctty)
  360.           err_fd = fd;
  361.       }
  362.       }
  363.  
  364.     /* Install the new standard I/O channels. */
  365.     if ((in_fd >= 0) && (in_fd != STDIN_FILENO))
  366.       {
  367.     if ((out_fd == STDIN_FILENO) && ((out_fd = (UX_dup (out_fd))) < 0))
  368.       goto kill_child;
  369.     if ((err_fd == STDIN_FILENO) && ((err_fd = (UX_dup (err_fd))) < 0))
  370.       goto kill_child;
  371.     if ((UX_dup2 (in_fd, STDIN_FILENO)) < 0)
  372.       goto kill_child;
  373.       }
  374.     if ((out_fd >= 0) && (out_fd != STDOUT_FILENO))
  375.       {
  376.     if ((err_fd == STDOUT_FILENO) && ((err_fd = (UX_dup (err_fd))) < 0))
  377.       goto kill_child;
  378.     if ((UX_dup2 (out_fd, STDOUT_FILENO)) < 0)
  379.       goto kill_child;
  380.       }
  381.     if ((err_fd >= 0) && (err_fd != STDERR_FILENO))
  382.       {
  383.     if ((UX_dup2 (err_fd, STDERR_FILENO)) < 0)
  384.       goto kill_child;
  385.       }
  386.   }
  387.   {
  388.     /* Close all other file descriptors. */
  389.     int fd = 0;
  390.     int open_max = (UX_SC_OPEN_MAX ());
  391.     while (fd < open_max)
  392.       {
  393.     if ((fd == STDIN_FILENO)
  394.         ? (channel_in_type == process_channel_type_none)
  395.         : (fd == STDOUT_FILENO)
  396.         ? (channel_out_type == process_channel_type_none)
  397.         : (fd == STDERR_FILENO)
  398.         ? (channel_err_type == process_channel_type_none)
  399.         : 1)
  400.       UX_close (fd);
  401.     fd += 1;
  402.       }
  403.   }
  404.  
  405.   /* Put the signal mask and handlers in a normal state.  */
  406.   UX_initialize_child_signals ();
  407.  
  408.   /* Start the process. */
  409.   execve (filename, ((char * CONST *) argv), ((char * CONST *) envp));
  410.  kill_child:
  411.   _exit (1);
  412. }
  413.  
  414. #define DEFUN_PROCESS_ACCESSOR(name, result_type, accessor)        \
  415. result_type                                \
  416. DEFUN (name, (process), Tprocess process)                \
  417. {                                    \
  418.   return (accessor (process));                        \
  419. }
  420.  
  421. DEFUN_PROCESS_ACCESSOR (OS_process_id, pid_t, PROCESS_ID)
  422. DEFUN_PROCESS_ACCESSOR (OS_process_status, enum process_status, PROCESS_STATUS)
  423. DEFUN_PROCESS_ACCESSOR (OS_process_reason, unsigned short, PROCESS_REASON)
  424. DEFUN_PROCESS_ACCESSOR
  425.   (OS_process_jc_status, enum process_jc_status, PROCESS_JC_STATUS)
  426.  
  427. int
  428. DEFUN (OS_process_valid_p, (process), Tprocess process)
  429. {
  430.   switch (PROCESS_RAW_STATUS (process))
  431.     {
  432.     case process_status_exited:
  433.     case process_status_signalled:
  434.     case process_status_stopped:
  435.     case process_status_running:
  436.       return (1);
  437.     default:
  438.       return (0);
  439.     }
  440. }
  441.  
  442. int
  443. DEFUN (OS_process_continuable_p, (process), Tprocess process)
  444. {
  445.   switch (PROCESS_RAW_STATUS (process))
  446.     {
  447.     case process_status_stopped:
  448.     case process_status_running:
  449.       return (1);
  450.     default:
  451.       return (0);
  452.     }
  453. }
  454.  
  455. int
  456. DEFUN (OS_process_foregroundable_p, (process), Tprocess process)
  457. {
  458.   switch (PROCESS_JC_STATUS (process))
  459.     {
  460.     case process_jc_status_no_jc:
  461.     case process_jc_status_jc:
  462.       return (1);
  463.     default:
  464.       return (0);
  465.     }
  466. }
  467.  
  468. int
  469. DEFUN (OS_process_status_sync, (process), Tprocess process)
  470. {
  471.   transaction_begin ();
  472.   block_sigchld ();
  473.   {
  474.     int result = ((PROCESS_TICK (process)) != (PROCESS_SYNC_TICK (process)));
  475.     if (result) PROCESS_STATUS_SYNC (process);
  476.     transaction_commit ();
  477.     return (result);
  478.   }
  479. }
  480.  
  481. int
  482. DEFUN_VOID (OS_process_status_sync_all)
  483. {
  484.   transaction_begin ();
  485.   block_sigchld ();
  486.   {
  487.     int result = (process_tick != sync_tick);
  488.     if (result) sync_tick = process_tick;
  489.     transaction_commit ();
  490.     return (result);
  491.   }
  492. }
  493.  
  494. int
  495. DEFUN_VOID (OS_process_any_status_change)
  496. {
  497.   return (process_tick != sync_tick);
  498. }
  499.  
  500. void
  501. DEFUN (OS_process_send_signal, (process, sig), Tprocess process AND int sig)
  502. {
  503.   STD_VOID_SYSTEM_CALL
  504.     (syscall_kill, 
  505.      (UX_kill ((((PROCESS_JC_STATUS (process)) == process_jc_status_jc)
  506.         ? (- (PROCESS_ID (process)))
  507.         : (PROCESS_ID (process))),
  508.            sig)));
  509. }
  510.  
  511. void
  512. DEFUN (OS_process_kill, (process), Tprocess process)
  513. {
  514.   OS_process_send_signal (process, SIGKILL);
  515. }
  516.  
  517. void
  518. DEFUN (OS_process_stop, (process), Tprocess process)
  519. {
  520.   OS_process_send_signal (process, SIGTSTP);
  521. }
  522.  
  523. void
  524. DEFUN (OS_process_interrupt, (process), Tprocess process)
  525. {
  526.   OS_process_send_signal (process, SIGINT);
  527. }
  528.  
  529. void
  530. DEFUN (OS_process_quit, (process), Tprocess process)
  531. {
  532.   OS_process_send_signal (process, SIGQUIT);
  533. }
  534.  
  535. void
  536. DEFUN (OS_process_hangup, (process), Tprocess process)
  537. {
  538.   OS_process_send_signal (process, SIGHUP);
  539. }
  540.  
  541. void
  542. DEFUN (OS_process_continue_background, (process), Tprocess process)
  543. {
  544.   transaction_begin ();
  545.   block_sigchld ();
  546.   if ((PROCESS_RAW_STATUS (process)) == process_status_stopped)
  547.     {
  548.       NEW_RAW_STATUS (process, process_status_running, 0);
  549.       OS_process_send_signal (process, SIGCONT);
  550.     }
  551.   transaction_commit ();
  552. }
  553.  
  554. void
  555. DEFUN (OS_process_continue_foreground, (process), Tprocess process)
  556. {
  557.   transaction_begin ();
  558.   grab_signal_mask ();
  559.   block_jc_signals ();
  560.   give_terminal_to (process);
  561.   if ((PROCESS_RAW_STATUS (process)) == process_status_stopped)
  562.     {
  563.       NEW_RAW_STATUS (process, process_status_running, 0);
  564.       OS_process_send_signal (process, SIGCONT); 
  565.     }
  566.   process_wait (process);
  567.   transaction_commit ();
  568. }
  569.  
  570. void
  571. DEFUN (OS_process_wait, (process), Tprocess process)
  572. {
  573.   transaction_begin ();
  574.   grab_signal_mask ();
  575.   block_jc_signals ();
  576.   process_wait (process);
  577.   transaction_commit ();
  578. }
  579.  
  580. static void
  581. DEFUN (get_terminal_back_1, (environment), PTR environment)
  582. {
  583.   get_terminal_back ();
  584. }
  585.  
  586. static void
  587. DEFUN (give_terminal_to, (process), Tprocess process)
  588. {
  589.   if (((PROCESS_JC_STATUS (process)) == process_jc_status_jc)
  590.       && (SCHEME_IN_FOREGROUND ()))
  591.     {
  592.       transaction_record_action (tat_always, get_terminal_back_1, 0);
  593.       foreground_child_process = process;
  594.       OS_save_internal_state ();
  595.       OS_restore_external_state ();
  596.       UX_tcsetpgrp (scheme_ctty_fd, (PROCESS_ID (process)));
  597.     }
  598. }
  599.  
  600. static void
  601. DEFUN_VOID (get_terminal_back)
  602. {
  603.   if (foreground_child_process != NO_PROCESS)
  604.     {
  605.       UX_tcsetpgrp (scheme_ctty_fd, (UX_getpgrp ()));
  606.       OS_save_external_state ();
  607.       OS_restore_internal_state ();
  608.       foreground_child_process = NO_PROCESS;
  609.     }
  610. }
  611.  
  612. static void
  613. DEFUN (process_wait, (process), Tprocess process)
  614. {
  615. #ifdef HAVE_POSIX_SIGNALS
  616.   while (((PROCESS_RAW_STATUS (process)) == process_status_running)
  617.      && (! (pending_interrupts_p ())))
  618.     UX_sigsuspend (&grabbed_signal_mask);
  619. #else /* not HAVE_POSIX_SIGNALS */
  620.   enum process_status status = (PROCESS_RAW_STATUS (process));
  621.   while ((status == process_status_running)
  622.      && (! (pending_interrupts_p ())))
  623.     {
  624.       /* INTERRUPTABLE_EXTENT eliminates the interrupt window between
  625.      PROCESS_RAW_STATUS and `pause'. */
  626.       int scr;
  627.       INTERRUPTABLE_EXTENT
  628.     (scr,
  629.      ((((status = (PROCESS_RAW_STATUS (process)))
  630.         == process_status_running)
  631.        && (! (pending_interrupts_p ())))
  632.       ? (UX_pause ())
  633.       : ((errno = EINTR), (-1))));
  634.     }
  635. #endif /* not HAVE_POSIX_SIGNALS */
  636. }
  637.  
  638. static Tprocess
  639. DEFUN (find_process, (pid), pid_t pid)
  640. {
  641.   Tprocess process;
  642.   for (process = 0; (process < OS_process_table_size); process += 1)
  643.     if ((PROCESS_ID (process)) == pid)
  644.       return (process);
  645.   return (NO_PROCESS);
  646. }
  647.  
  648. static void
  649. DEFUN (subprocess_death, (pid, status), pid_t pid AND int * status)
  650. {
  651.   Tprocess process = (find_process (pid));
  652.   if (process != NO_PROCESS)
  653.     {
  654.       if (WIFEXITED (*status))
  655.     {
  656.       NEW_RAW_STATUS
  657.         (process, process_status_exited, (WEXITSTATUS (*status)));
  658.     }
  659.       else if (WIFSTOPPED (*status))
  660.     {
  661.       NEW_RAW_STATUS
  662.         (process, process_status_stopped, (WSTOPSIG (*status)));
  663.     }
  664.       else if (WIFSIGNALED (*status))
  665.     {
  666.       NEW_RAW_STATUS
  667.         (process, process_status_signalled, (WTERMSIG (*status)));
  668.     }
  669.     }
  670. }
  671.  
  672. static void
  673. DEFUN (stop_signal_handler, (signo), int signo)
  674. {
  675.   /* If Scheme gets a stop signal while waiting on a foreground
  676.      subprocess, it must grab the terminal back from the subprocess
  677.      before stopping.  The caller guarantees that the job-control
  678.      signals are blocked when this procedure is called. */
  679.   get_terminal_back ();
  680.   stop_signal_default (signo);
  681. }
  682.  
  683. /* Set up the terminal at the other end of a pseudo-terminal that we
  684.    will be controlling an inferior through. */
  685.  
  686. #ifdef HAVE_TERMIOS_H
  687.  
  688. /* POSIX.1 doesn't require (or even mention) these symbols, but we
  689.    must disable them if they are present. */
  690. #ifndef IUCLC
  691. #  define IUCLC 0
  692. #endif
  693. #ifndef OLCUC
  694. #  define OLCUC 0
  695. #endif
  696. #ifndef NLDLY
  697. #  define NLDLY 0
  698. #endif
  699. #ifndef CRDLY
  700. #  define CRDLY 0
  701. #endif
  702. #ifndef TABDLY
  703. #  define TABDLY 0
  704. #endif
  705. #ifndef BSDLY
  706. #  define BSDLY 0
  707. #endif
  708. #ifndef VTDLY
  709. #  define VTDLY 0
  710. #endif
  711. #ifndef FFDLY
  712. #  define FFDLY 0
  713. #endif
  714. #ifndef ONLCR
  715. #  define ONLCR 0
  716. #endif
  717.  
  718. static int
  719. DEFUN (child_setup_tty, (fd), int fd)
  720. {
  721.   cc_t disabled_char = (UX_PC_VDISABLE (fd));
  722.   struct termios s;
  723.   if ((UX_tcgetattr (fd, (&s))) < 0)
  724.     return (-1);
  725.   (s . c_iflag) &=~ IUCLC;
  726.   (s . c_oflag) |= OPOST;
  727.   (s . c_oflag) &=~
  728.     (OLCUC | ONLCR | NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY);
  729.   (s . c_lflag) &=~ (ECHO | ECHOE | ECHOK | ECHONL);
  730.   (s . c_lflag) |= (ICANON | ISIG);
  731.   ((s . c_cc) [VEOF]) = '\004';
  732.   ((s . c_cc) [VERASE]) = disabled_char;
  733.   ((s . c_cc) [VKILL]) = disabled_char;
  734.   cfsetispeed ((&s), B9600);
  735.   cfsetospeed ((&s), B9600);
  736.   return (UX_tcsetattr (fd, TCSADRAIN, (&s)));
  737. }
  738.  
  739. #else /* not HAVE_TERMIOS_H */
  740.  
  741. #ifdef HAVE_TERMIO_H
  742.  
  743. static int
  744. DEFUN (child_setup_tty, (fd), int fd)
  745. {
  746.   cc_t disabled_char = (UX_PC_VDISABLE (fd));
  747.   struct termio s;
  748.   if ((ioctl (fd, TCGETA, (&s))) < 0)
  749.     return (-1);
  750.   (s . c_iflag) &=~ IUCLC;
  751.   (s . c_oflag) |= OPOST;
  752.   (s . c_oflag) &=~
  753.     (OLCUC | ONLCR | NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY);
  754.   (s . c_lflag) &=~ (ECHO | ECHOE | ECHOK | ECHONL);
  755.   (s . c_lflag) |= (ICANON | ISIG);
  756.   ((s . c_cc) [VEOF]) = '\004';
  757.   ((s . c_cc) [VERASE]) = disabled_char;
  758.   ((s . c_cc) [VKILL]) = disabled_char;
  759.   (s . c_cflag) = (((s . c_cflag) &~ CBAUD) | B9600);
  760. #ifdef _AIX
  761.   /* AIX enhanced edit loses NULs, so disable it.
  762.      Also, PTY overloads NUL and BREAK.
  763.      don't ignore break, but don't signal either, so it looks like NUL.
  764.      This really serves a purpose only if running in an XTERM window
  765.      or via TELNET or the like, but does no harm elsewhere.  */
  766.   (s . c_line) = 0;
  767.   (s . c_iflag) &=~ (ASCEDIT | IGNBRK | BRKINT);
  768.   /* QUIT and INTR work better as signals, so disable character forms */
  769.   (s . c_lflag) &=~ ISIG;
  770.   ((s . c_cc) [VQUIT]) = disabled_char;
  771.   ((s . c_cc) [VINTR]) = disabled_char;
  772.   ((s . c_cc) [VEOL]) = disabled_char;
  773. #endif /* _AIX */
  774.   return (ioctl (fd, TCSETAW, (&s)));
  775. }
  776.  
  777. #else /* not HAVE_TERMIO_H */
  778. #ifdef HAVE_SGTTY_H
  779.  
  780. static int
  781. DEFUN (child_setup_tty, (fd), int fd)
  782. {
  783.   struct sgttyb s;
  784.   if ((ioctl (fd, TIOCGETP, (&s))) < 0)
  785.     return (-1);
  786.   (s . sg_flags) &=~
  787.     (ECHO | CRMOD | ANYP | ALLDELAY | RAW | LCASE | CBREAK | TANDEM);
  788.   return (ioctl (fd, TIOCSETN, (&s)));
  789. }
  790.  
  791. #endif /* HAVE_SGTTY_H */
  792. #endif /* HAVE_TERMIO_H */
  793. #endif /* HAVE_TERMIOS_H */
  794.