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 / prosproc.c < prev    next >
C/C++ Source or Header  |  2000-12-05  |  13KB  |  386 lines

  1. /* -*-C-*-
  2.  
  3. $Id: prosproc.c,v 1.19 2000/12/05 21:23:47 cph Exp $
  4.  
  5. Copyright (c) 1990-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. /* Primitives for subprocess control. */
  23.  
  24. #include "scheme.h"
  25. #include "prims.h"
  26. #include "osproc.h"
  27. #include "osio.h"
  28.  
  29. #ifdef __unix__
  30.    extern char ** environ;
  31. #endif
  32.  
  33. extern Tchannel EXFUN (arg_channel, (int));
  34.  
  35. static Tprocess
  36. DEFUN (arg_process, (argument_number), int argument_number)
  37. {
  38.   Tprocess process =
  39.     (arg_index_integer (argument_number, OS_process_table_size));
  40.   if (! (OS_process_valid_p (process)))
  41.     error_bad_range_arg (argument_number);
  42.   return (process);
  43. }
  44.  
  45. DEFINE_PRIMITIVE ("SCHEME-ENVIRONMENT", Prim_scheme_environment, 0, 0, 0)
  46. {
  47.   PRIMITIVE_HEADER (0);
  48.   {
  49.     char ** scan_environ = environ;
  50.     char ** end_environ = scan_environ;
  51.     while ((*end_environ++) != 0) ;
  52.     end_environ -= 1;
  53.     {
  54.       SCHEME_OBJECT result =
  55.     (allocate_marked_vector (TC_VECTOR, (end_environ - environ), 1));
  56.       SCHEME_OBJECT * scan_result = (VECTOR_LOC (result, 0));
  57.       while (scan_environ < end_environ)
  58.     (*scan_result++) =
  59.       (char_pointer_to_string ((unsigned char *) (*scan_environ++)));
  60.       PRIMITIVE_RETURN (result);
  61.     }
  62.   }
  63. }
  64.  
  65. DEFINE_PRIMITIVE ("PROCESS-DELETE", Prim_process_delete, 1, 1,
  66.   "Delete process PROCESS-NUMBER from the process table.")
  67. {
  68.   PRIMITIVE_HEADER (1);
  69.   OS_process_deallocate (arg_process (1));
  70.   PRIMITIVE_RETURN (UNSPECIFIC);
  71. }
  72.  
  73. DEFINE_PRIMITIVE ("PROCESS-TABLE", Prim_process_table, 0, 0,
  74.   "Return a vector of all processes in the process table.")
  75. {
  76.   PRIMITIVE_HEADER (0);
  77.   {
  78.     Tprocess process;
  79.     for (process = 0; (process < OS_process_table_size); process += 1)
  80.       if (OS_process_valid_p (process))
  81.     obstack_grow ((&scratch_obstack), (&process), (sizeof (Tprocess)));
  82.   }
  83.   {
  84.     unsigned int n_processes =
  85.       ((obstack_object_size ((&scratch_obstack))) / (sizeof (Tprocess)));
  86.     if (n_processes == 0)
  87.       PRIMITIVE_RETURN (SHARP_F);
  88.     {
  89.       Tprocess * processes = (obstack_finish (&scratch_obstack));
  90.       Tprocess * scan_processes = processes;
  91.       SCHEME_OBJECT vector =
  92.     (allocate_marked_vector (TC_VECTOR, n_processes, 1));
  93.       SCHEME_OBJECT * scan_vector = (VECTOR_LOC (vector, 0));
  94.       SCHEME_OBJECT * end_vector = (scan_vector + n_processes);
  95.       while (scan_vector < end_vector)
  96.     (*scan_vector++) = (long_to_integer (*scan_processes++));
  97.       obstack_free ((&scratch_obstack), processes);
  98.       PRIMITIVE_RETURN (vector);
  99.     }
  100.   }
  101. }
  102.  
  103. DEFINE_PRIMITIVE ("PROCESS-ID", Prim_process_id, 1, 1, 
  104.   "Return the process ID of process PROCESS-NUMBER.")
  105. {
  106.   PRIMITIVE_HEADER (1);
  107.   PRIMITIVE_RETURN (ulong_to_integer (OS_process_id (arg_process (1))));
  108. }
  109.  
  110. DEFINE_PRIMITIVE ("PROCESS-JOB-CONTROL-STATUS", Prim_process_jc_status, 1, 1, 
  111.   "Returns the job-control status of process PROCESS-NUMBER:\n\
  112.   0 means this system doesn't support job control.\n\
  113.   1 means the process doesn't have the same controlling terminal as Scheme.\n\
  114.   2 means it's the same ctty but the OS doesn't have job control.\n\
  115.   3 means it's the same ctty and the OS has job control.")
  116. {
  117.   PRIMITIVE_HEADER (1);
  118.   switch (OS_process_jc_status (arg_process (1)))
  119.     {
  120.     case process_jc_status_no_ctty:
  121.       PRIMITIVE_RETURN (LONG_TO_UNSIGNED_FIXNUM (0));
  122.     case process_jc_status_unrelated:
  123.       PRIMITIVE_RETURN (LONG_TO_UNSIGNED_FIXNUM (1));
  124.     case process_jc_status_no_jc:
  125.       PRIMITIVE_RETURN (LONG_TO_UNSIGNED_FIXNUM (2));
  126.     case process_jc_status_jc:
  127.       PRIMITIVE_RETURN (LONG_TO_UNSIGNED_FIXNUM (3));
  128.     default:
  129.       error_bad_range_arg (1);
  130.       PRIMITIVE_RETURN (UNSPECIFIC);
  131.     }
  132. }
  133.  
  134. DEFINE_PRIMITIVE ("PROCESS-STATUS-SYNC", Prim_process_status_sync, 1, 1,
  135.   "Synchronize the status of process PROCESS-NUMBER.\n\
  136. Return #F if it was previously synchronized, #T if not.")
  137. {
  138.   PRIMITIVE_HEADER (1);
  139.   PRIMITIVE_RETURN
  140.     (BOOLEAN_TO_OBJECT (OS_process_status_sync (arg_process (1))));
  141. }
  142.  
  143. DEFINE_PRIMITIVE ("PROCESS-STATUS-SYNC-ALL", Prim_process_status_sync_all, 0, 0, 0)
  144. {
  145.   PRIMITIVE_HEADER (0);
  146.   PRIMITIVE_RETURN (BOOLEAN_TO_OBJECT (OS_process_status_sync_all ()));
  147. }
  148.  
  149. DEFINE_PRIMITIVE ("PROCESS-STATUS", Prim_process_status, 1, 1,
  150.   "Return the status of process PROCESS-NUMBER, a nonnegative integer:\n\
  151.   0 = running; 1 = stopped; 2 = exited; 3 = signalled.\n\
  152. The value is from the last synchronization.")
  153. {
  154.   PRIMITIVE_HEADER (1);
  155.   switch (OS_process_status (arg_process (1)))
  156.     {
  157.     case process_status_running:
  158.       PRIMITIVE_RETURN (LONG_TO_UNSIGNED_FIXNUM (0));
  159.     case process_status_stopped:
  160.       PRIMITIVE_RETURN (LONG_TO_UNSIGNED_FIXNUM (1));
  161.     case process_status_exited:
  162.       PRIMITIVE_RETURN (LONG_TO_UNSIGNED_FIXNUM (2));
  163.     case process_status_signalled:
  164.       PRIMITIVE_RETURN (LONG_TO_UNSIGNED_FIXNUM (3));
  165.     default:
  166.       error_external_return ();
  167.       PRIMITIVE_RETURN (UNSPECIFIC);
  168.     }
  169. }
  170.  
  171. DEFINE_PRIMITIVE ("PROCESS-REASON", Prim_process_reason, 1, 1, 
  172.   "Return the termination reason of process PROCESS-NUMBER.\n\
  173. This is a nonnegative integer, which depends on the process's status:\n\
  174.   running => zero;\n\
  175.   stopped => the signal that stopped the process;\n\
  176.   exited => the exit code returned by the process;\n\
  177.   signalled => the signal that killed the process.\n\
  178. The value is from the last synchronization.")
  179. {
  180.   PRIMITIVE_HEADER (1);
  181.   PRIMITIVE_RETURN (long_to_integer (OS_process_reason (arg_process (1))));
  182. }
  183.  
  184. DEFINE_PRIMITIVE ("PROCESS-SIGNAL", Prim_process_signal, 2, 2,
  185.   "Send a signal to process PROCESS-NUMBER; second arg SIGNAL says which one.")
  186. {
  187.   PRIMITIVE_HEADER (2);
  188.   OS_process_send_signal ((arg_process (1)), (arg_nonnegative_integer (2)));
  189.   PRIMITIVE_RETURN (UNSPECIFIC);
  190. }
  191.  
  192. #define PROCESS_SIGNALLING_PRIMITIVE(signaller)                \
  193. {                                    \
  194.   PRIMITIVE_HEADER (1);                            \
  195.   signaller (arg_process (1));                        \
  196.   PRIMITIVE_RETURN (UNSPECIFIC);                    \
  197. }
  198.  
  199. DEFINE_PRIMITIVE ("PROCESS-KILL", Prim_process_kill, 1, 1,
  200.   "Kills process PROCESS-NUMBER (unix SIGKILL).")
  201.      PROCESS_SIGNALLING_PRIMITIVE (OS_process_kill)
  202.  
  203. DEFINE_PRIMITIVE ("PROCESS-INTERRUPT", Prim_process_interrupt, 1, 1,
  204.   "Interrupts process PROCESS-NUMBER (unix SIGINT).")
  205.      PROCESS_SIGNALLING_PRIMITIVE (OS_process_interrupt)
  206.  
  207. DEFINE_PRIMITIVE ("PROCESS-QUIT", Prim_process_quit, 1, 1,
  208.   "Sends the quit signal to process PROCESS-NUMBER (unix SIGQUIT).")
  209.      PROCESS_SIGNALLING_PRIMITIVE (OS_process_quit)
  210.  
  211. DEFINE_PRIMITIVE ("PROCESS-HANGUP", Prim_process_hangup, 1, 1,
  212.   "Sends the hangup signal to process PROCESS-NUMBER (unix SIGHUP).")
  213.      PROCESS_SIGNALLING_PRIMITIVE (OS_process_hangup)
  214.  
  215. DEFINE_PRIMITIVE ("PROCESS-STOP", Prim_process_stop, 1, 1,
  216.   "Stops process PROCESS-NUMBER (unix SIGTSTP).")
  217.      PROCESS_SIGNALLING_PRIMITIVE (OS_process_stop)
  218.  
  219. DEFINE_PRIMITIVE ("PROCESS-CONTINUE-BACKGROUND", Prim_process_continue_background, 1, 1,
  220.   "Continues process PROCESS-NUMBER in the background.")
  221. {
  222.   PRIMITIVE_HEADER (1);
  223.   {
  224.     Tprocess process = (arg_process (1));
  225.     if (! (OS_process_continuable_p (process)))
  226.       error_bad_range_arg (1);
  227.     OS_process_continue_background (process);
  228.   }
  229.   PRIMITIVE_RETURN (UNSPECIFIC);
  230. }
  231.  
  232. DEFINE_PRIMITIVE ("PROCESS-WAIT", Prim_process_wait, 1, 1,
  233.   "Waits until process PROCESS-NUMBER is not running.")
  234. {
  235.   PRIMITIVE_HEADER (1);
  236.   OS_process_wait (arg_process (1));
  237.   PRIMITIVE_RETURN (UNSPECIFIC);
  238. }
  239.  
  240. DEFINE_PRIMITIVE ("PROCESS-CONTINUE-FOREGROUND", Prim_process_continue_foreground, 1, 1,
  241.   "Continues process PROCESS-NUMBER in the foreground.\n\
  242. The process must have the same controlling terminal as Scheme.")
  243. {
  244.   PRIMITIVE_HEADER (1);
  245.   {
  246.     Tprocess process = (arg_process (1));
  247.     if (! ((OS_process_foregroundable_p (process))
  248.        && (OS_process_continuable_p (process))))
  249.       error_bad_range_arg (1);
  250.     OS_process_continue_foreground (process);
  251.     PRIMITIVE_RETURN (UNSPECIFIC);
  252.   }
  253. }
  254.  
  255. /* This primitive is obsolete.  */
  256.  
  257. static int EXFUN (string_vector_p, (SCHEME_OBJECT vector));
  258. static CONST char ** EXFUN (convert_string_vector, (SCHEME_OBJECT vector));
  259.  
  260. #define PROCESS_CHANNEL_ARG(arg, type, channel)                \
  261. {                                    \
  262.   if ((ARG_REF (arg)) == SHARP_F)                    \
  263.     (type) = process_channel_type_none;                    \
  264.   else if ((ARG_REF (arg)) == (LONG_TO_FIXNUM (-1)))            \
  265.     (type) = process_channel_type_inherit;                \
  266.   else if ((ARG_REF (arg)) == (LONG_TO_FIXNUM (-2)))            \
  267.     {                                    \
  268.       if (ctty_type != process_ctty_type_explicit)            \
  269.     error_bad_range_arg (arg);                    \
  270.       (type) = process_channel_type_ctty;                \
  271.     }                                    \
  272.   else                                    \
  273.     {                                    \
  274.       (type) = process_channel_type_explicit;                \
  275.       (channel) = (arg_channel (arg));                    \
  276.     }                                    \
  277. }
  278.  
  279. DEFINE_PRIMITIVE ("MAKE-SUBPROCESS", Prim_make_subprocess, 7, 7,
  280.   "Create a subprocess.\n\
  281. First arg FILENAME is the program to run.\n\
  282. Second arg ARGV is a vector of strings to pass to the program as arguments.\n\
  283. Third arg ENV is a vector of strings to pass as the program's environment;\n\
  284.   #F means inherit Scheme's environment.\n\
  285. Fourth arg CTTY specifies the program's controlling terminal:\n\
  286.   #F means none;\n\
  287.   -1 means use Scheme's controlling terminal in background;\n\
  288.   -2 means use Scheme's controlling terminal in foreground;\n\
  289.   string means open that terminal.\n\
  290. Fifth arg STDIN is the input channel for the subprocess.\n\
  291. Sixth arg STDOUT is the output channel for the subprocess.\n\
  292. Seventh arg STDERR is the error channel for the subprocess.\n\
  293.   Each channel arg can take these values:\n\
  294.   #F means none;\n\
  295.   -1 means use the corresponding channel from Scheme;\n\
  296.   -2 means use the controlling terminal (valid only when CTTY is a string);\n\
  297.   otherwise the argument must be a channel.")
  298. {
  299.   PRIMITIVE_HEADER (7);
  300.   CHECK_ARG (2, string_vector_p);
  301.   {
  302.     PTR position = dstack_position;
  303.     CONST char * filename = (STRING_ARG (1));
  304.     CONST char ** argv = (convert_string_vector (ARG_REF (2)));
  305.     SCHEME_OBJECT env_object = (ARG_REF (3));
  306.     CONST char ** env = 0;
  307.     CONST char * working_directory = 0;
  308.     enum process_ctty_type ctty_type;
  309.     char * ctty_name = 0;
  310.     enum process_channel_type channel_in_type;
  311.     Tchannel channel_in = NO_CHANNEL;
  312.     enum process_channel_type channel_out_type;
  313.     Tchannel channel_out = NO_CHANNEL;
  314.     enum process_channel_type channel_err_type;
  315.     Tchannel channel_err = NO_CHANNEL;
  316.  
  317.     if ((PAIR_P (env_object)) && (STRING_P (PAIR_CDR (env_object))))
  318.       {
  319.     working_directory =
  320.       ((CONST char *) (STRING_LOC ((PAIR_CDR (env_object)), 0)));
  321.     env_object = (PAIR_CAR (env_object));
  322.       }
  323.     if (env_object != SHARP_F)
  324.       {
  325.     if (! (string_vector_p (env_object)))
  326.       error_wrong_type_arg (3);
  327.     env = (convert_string_vector (env_object));
  328.       }
  329.     if ((ARG_REF (4)) == SHARP_F)
  330.       ctty_type = process_ctty_type_none;
  331.     else if ((ARG_REF (4)) == (LONG_TO_FIXNUM (-1)))
  332.       ctty_type = process_ctty_type_inherit_bg;
  333.     else if ((ARG_REF (4)) == (LONG_TO_FIXNUM (-2)))
  334.       ctty_type = process_ctty_type_inherit_fg;
  335.     else
  336.       {
  337.     ctty_type = process_ctty_type_explicit;
  338.     ctty_name = (STRING_ARG (4));
  339.       }
  340.     PROCESS_CHANNEL_ARG (5, channel_in_type, channel_in);
  341.     PROCESS_CHANNEL_ARG (6, channel_out_type, channel_out);
  342.     PROCESS_CHANNEL_ARG (7, channel_err_type, channel_err);
  343.     {
  344.       Tprocess process =
  345.     (OS_make_subprocess
  346.      (filename, argv, env, working_directory,
  347.       ctty_type, ctty_name,
  348.       channel_in_type, channel_in,
  349.       channel_out_type, channel_out,
  350.       channel_err_type, channel_err));
  351.       dstack_set_position (position);
  352.       PRIMITIVE_RETURN (long_to_integer (process));
  353.     }
  354.   }
  355. }
  356.  
  357. static int
  358. DEFUN (string_vector_p, (vector), SCHEME_OBJECT vector)
  359. {
  360.   if (! (VECTOR_P (vector)))
  361.     return (0);
  362.   {
  363.     unsigned long length = (VECTOR_LENGTH (vector));
  364.     SCHEME_OBJECT * scan = (VECTOR_LOC (vector, 0));
  365.     SCHEME_OBJECT * end = (scan + length);
  366.     while (scan < end)
  367.       if (! (STRING_P (*scan++)))
  368.     return (0);
  369.   }
  370.   return (1);
  371. }
  372.  
  373. static CONST char **
  374. DEFUN (convert_string_vector, (vector), SCHEME_OBJECT vector)
  375. {
  376.   unsigned long length = (VECTOR_LENGTH (vector));
  377.   char ** result = (dstack_alloc ((length + 1) * (sizeof (char *))));
  378.   SCHEME_OBJECT * scan = (VECTOR_LOC (vector, 0));
  379.   SCHEME_OBJECT * end = (scan + length);
  380.   char ** scan_result = result;
  381.   while (scan < end)
  382.     (*scan_result++) = ((char *) (STRING_LOC ((*scan++), 0)));
  383.   (*scan_result) = 0;
  384.   return ((CONST char **) result);
  385. }
  386.