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 / os2proc.c < prev    next >
C/C++ Source or Header  |  2000-12-05  |  17KB  |  627 lines

  1. /* -*-C-*-
  2.  
  3. $Id: os2proc.c,v 1.7 2000/12/05 21:23:46 cph Exp $
  4.  
  5. Copyright (c) 1995-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. #include "os2.h"
  23. #include "osproc.h"
  24. #include "osenv.h"
  25.  
  26. extern const char * OS_working_dir_pathname (void);
  27.  
  28. typedef struct
  29. {
  30.   PID id;
  31.   unsigned long tick;
  32.   unsigned long sync_tick;
  33.   ULONG raw_reason;
  34.   ULONG reason;
  35.   enum process_status raw_status;
  36.   enum process_status status;
  37. } process_t;
  38. #define _PROCESS(process) (process_table [(process)])
  39. #define PROCESS_ID(process) ((_PROCESS(process)) . id)
  40. #define PROCESS_TICK(process) ((_PROCESS(process)) . tick)
  41. #define PROCESS_SYNC_TICK(process) ((_PROCESS(process)) . sync_tick)
  42. #define PROCESS_RAW_REASON(process) ((_PROCESS(process)) . raw_reason)
  43. #define PROCESS_REASON(process) ((_PROCESS(process)) . reason)
  44. #define PROCESS_RAW_STATUS(process) ((_PROCESS(process)) . raw_status)
  45. #define PROCESS_STATUS(process) ((_PROCESS(process)) . status)
  46.  
  47. typedef struct
  48. {
  49.   DECLARE_MSG_HEADER_FIELDS;
  50.   PID pid;
  51. } sm_child_death_t;
  52. #define SM_CHILD_DEATH_PID(m) (((sm_child_death_t *) (m)) -> pid)
  53.  
  54. static void lock_process_status (void);
  55. static void unlock_process_status (void *);
  56. static void save_process_state (int);
  57. static HFILE copy_handle (HFILE);
  58. static int valid_handle_p (HFILE);
  59. static void restore_process_state (void *);
  60. static void restore_stdio (HFILE, HFILE);
  61. static void transfer_stdio (HFILE, Tchannel, enum process_channel_type);
  62. static Tprocess allocate_process (void);
  63. static void allocate_process_abort (void *);
  64. static void child_wait_thread (void *);
  65. static Tprocess find_process (PID);
  66.  
  67. size_t OS_process_table_size;
  68. enum process_jc_status scheme_jc_status;
  69.  
  70. static HMTX process_lock;
  71. static process_t * process_table;
  72. static unsigned long process_tick;
  73. static unsigned long sync_tick;
  74. static HEV start_child_event;
  75. TID OS2_child_wait_tid;
  76. static qid_t child_wait_qid_reader;
  77. static qid_t child_wait_qid_writer;
  78.  
  79. #define PROCESS_STATUS_SYNC(process)                    \
  80. {                                    \
  81.   (PROCESS_STATUS (process)) = (PROCESS_RAW_STATUS (process));        \
  82.   (PROCESS_REASON (process)) = (PROCESS_RAW_REASON (process));        \
  83.   (PROCESS_SYNC_TICK (process)) = (PROCESS_TICK (process));        \
  84. }
  85.  
  86. static void
  87. lock_process_status (void)
  88. {
  89.   OS2_request_mutex_semaphore (process_lock);
  90.   transaction_record_action (tat_always, unlock_process_status, 0);
  91. }
  92.  
  93. static void
  94. unlock_process_status (void * ignore)
  95. {
  96.   OS2_release_mutex_semaphore (process_lock);
  97. }
  98.  
  99. void
  100. OS2_initialize_processes (void)
  101. {
  102.   SET_MSG_TYPE_LENGTH (mt_child_death, sm_child_death_t);
  103.   OS_process_table_size = 4096;
  104.   process_table = (OS_malloc (OS_process_table_size * (sizeof (process_t))));
  105.   {
  106.     Tprocess process;
  107.     for (process = 0; (process < OS_process_table_size); process += 1)
  108.       OS_process_deallocate (process);
  109.   }
  110.   scheme_jc_status = process_jc_status_no_ctty;
  111.   process_tick = 0;
  112.   sync_tick = 0;
  113.   process_lock = (OS2_create_mutex_semaphore (0, 0));
  114.   start_child_event = (OS2_create_event_semaphore (0, 0));
  115.   OS2_make_qid_pair ((& child_wait_qid_reader), (& child_wait_qid_writer));
  116.   OS2_open_qid (child_wait_qid_reader, OS2_scheme_tqueue);
  117.   OS2_child_wait_tid = (OS2_beginthread (child_wait_thread, 0, 0));
  118. }
  119.  
  120. Tprocess
  121. OS2_make_subprocess (const char * filename,
  122.              const char * command_line,
  123.              const char * environment,
  124.              const char * working_directory,
  125.              enum process_channel_type channel_in_type,
  126.              Tchannel channel_in,
  127.              enum process_channel_type channel_out_type,
  128.              Tchannel channel_out,
  129.              enum process_channel_type channel_err_type,
  130.              Tchannel channel_err)
  131. {
  132.   transaction_begin ();
  133.   save_process_state (working_directory != 0);
  134.   transfer_stdio (0, channel_in, channel_in_type);
  135.   transfer_stdio (1, channel_out, channel_out_type);
  136.   transfer_stdio (2, channel_err, channel_err_type);
  137.   if (working_directory != 0)
  138.     OS_set_working_dir_pathname (working_directory);
  139.   {
  140.     Tprocess child;
  141.     char error_object [100];
  142.     RESULTCODES result_codes;
  143.  
  144.     lock_process_status ();
  145.     child = (allocate_process ());
  146.     STD_API_CALL
  147.       (dos_exec_pgm, (error_object,
  148.               (sizeof (error_object)),
  149.               EXEC_ASYNCRESULT,
  150.               ((PSZ) command_line),
  151.               ((PSZ) environment),
  152.               (& result_codes),
  153.               ((PSZ) filename)));
  154.     (PROCESS_ID (child)) = (result_codes . codeTerminate);
  155.     (PROCESS_RAW_STATUS (child)) = process_status_running;
  156.     (PROCESS_RAW_REASON (child)) = 0;
  157.     (PROCESS_TICK (child)) = process_tick;
  158.     PROCESS_STATUS_SYNC (child);
  159.     transaction_commit ();
  160.     /* Wake up the child-wait thread if it's sleeping.  */
  161.     (void) OS2_post_event_semaphore (start_child_event);
  162.     return (child);
  163.   }
  164. }
  165.  
  166. typedef struct
  167. {
  168.   HFILE std_in;
  169.   HFILE std_out;
  170.   HFILE std_err;
  171.   const char * working_directory;
  172.   int copied_p;
  173. } process_state_t;
  174.  
  175. static void
  176. save_process_state (int save_working_dir_p)
  177. {
  178.   process_state_t * state = (dstack_alloc (sizeof (process_state_t)));
  179.   (state -> std_in) = NULLHANDLE;
  180.   (state -> std_out) = NULLHANDLE;
  181.   (state -> std_err) = NULLHANDLE;
  182.   (state -> working_directory) = 0;
  183.   (state -> copied_p) = 0;
  184.   transaction_record_action (tat_always, restore_process_state, state);
  185.   if (valid_handle_p (0))
  186.     (state -> std_in) = (copy_handle (0));
  187.   if (valid_handle_p (1))
  188.     (state -> std_out) = (copy_handle (1));
  189.   if (valid_handle_p (2))
  190.     (state -> std_err) = (copy_handle (2));
  191.   if (save_working_dir_p)
  192.     {
  193.       const char * dir = (OS_working_dir_pathname ());
  194.       char * copy = (OS_malloc (strlen (dir)));
  195.       strcpy (copy, dir);
  196.       (state -> working_directory) = copy;
  197.     }
  198.   (state -> copied_p) = 1;
  199. }
  200.  
  201. static int
  202. valid_handle_p (HFILE handle)
  203. {
  204.   ULONG state;
  205.   return ((dos_query_fh_state (handle, (& state))) == NO_ERROR);
  206. }
  207.  
  208. static HFILE
  209. copy_handle (HFILE handle)
  210. {
  211.   HFILE target = (-1);
  212.   STD_API_CALL (dos_dup_handle, (handle, (& target)));
  213.   return (target);
  214. }
  215.  
  216. static void
  217. restore_process_state (void * env)
  218. {
  219.   process_state_t * state = env;
  220.   if (state -> copied_p)
  221.     {
  222.       restore_stdio (0, (state -> std_in));
  223.       restore_stdio (1, (state -> std_out));
  224.       restore_stdio (2, (state -> std_err));
  225.       if ((state -> working_directory) != 0)
  226.     {
  227.       OS_set_working_dir_pathname (state -> working_directory);
  228.       OS_free ((void *) (state -> working_directory));
  229.     }
  230.     }
  231.   if ((state -> std_in) != NULLHANDLE)
  232.     (void) dos_close (state -> std_in);
  233.   if ((state -> std_out) != NULLHANDLE)
  234.     (void) dos_close (state -> std_out);
  235.   if ((state -> std_err) != NULLHANDLE)
  236.     (void) dos_close (state -> std_err);
  237. }
  238.  
  239. static void
  240. restore_stdio (HFILE target, HFILE source)
  241. {
  242.   if (source != NULLHANDLE)
  243.     (void) dos_dup_handle (source, (& target));
  244.   else
  245.     (void) dos_close (target);
  246. }
  247.  
  248. static void
  249. transfer_stdio (HFILE target, Tchannel channel, enum process_channel_type type)
  250. {
  251.   switch (type)
  252.     {
  253.     case process_channel_type_none:
  254.       STD_API_CALL (dos_close, (target));
  255.       break;
  256.     case process_channel_type_explicit:
  257.       STD_API_CALL (dos_dup_handle, ((CHANNEL_HANDLE (channel)), (& target)));
  258.       break;
  259.     }
  260.   switch (type)
  261.     {
  262.     case process_channel_type_inherit:
  263.     case process_channel_type_explicit:
  264.       /* Turn off the no-inherit bit that is normally turned on by
  265.      Scheme.  Note that the no-inherit bit is not shared between a
  266.      dup'ed handle and its original handle, so that changing the
  267.      original does not affect the copy.  This simplifies restoring
  268.      the original state.  */
  269.       {
  270.     ULONG state;
  271.     STD_API_CALL (dos_query_fh_state, (target, (& state)));
  272.     /* Magic mask 0xFF88 zeroes out high bits and two fields
  273.        required to be zero by the spec.  When testing, the high
  274.        bits were not zero, and this caused the system call to
  275.        complain.  */
  276.     state &= 0xFF88;
  277.     STD_API_CALL
  278.       (dos_set_fh_state, (target, (state &~ OPEN_FLAGS_NOINHERIT)));
  279.       }
  280.       break;
  281.     }
  282. }
  283.  
  284. static Tprocess
  285. allocate_process (void)
  286. {
  287.   unsigned int process;
  288.   for (process = 0; (process < OS_process_table_size); process += 1)
  289.     if ((PROCESS_RAW_STATUS (process)) == process_status_free)
  290.       {
  291.     Tprocess * pp = (dstack_alloc (sizeof (Tprocess)));
  292.     (*pp) = process;
  293.     transaction_record_action (tat_abort, allocate_process_abort, pp);
  294.     (PROCESS_RAW_STATUS (process)) = process_status_allocated;
  295.     return (process);
  296.       }
  297.   error_out_of_processes ();
  298.   return (NO_PROCESS);
  299. }
  300.  
  301. static void
  302. allocate_process_abort (void * environment)
  303. {
  304.   Tprocess process = (* ((Tprocess *) environment));
  305.   if ((PROCESS_RAW_STATUS (process)) == process_status_running)
  306.     dos_kill_process (DKP_PROCESSTREE, (PROCESS_ID (process)));
  307.   OS_process_deallocate (process);
  308. }
  309.  
  310. void
  311. OS_process_deallocate (Tprocess process)
  312. {
  313.   (PROCESS_ID (process)) = 0;
  314.   (PROCESS_RAW_STATUS (process)) = process_status_free;
  315. }
  316.  
  317. int
  318. OS_process_valid_p (Tprocess process)
  319. {
  320.   switch (PROCESS_RAW_STATUS (process))
  321.     {
  322.     case process_status_exited:
  323.     case process_status_signalled:
  324.     case process_status_running:
  325.       return (1);
  326.     default:
  327.       return (0);
  328.     }
  329. }
  330.  
  331. int
  332. OS_process_continuable_p (Tprocess process)
  333. {
  334.   return ((PROCESS_RAW_STATUS (process)) == process_status_running);
  335. }
  336.  
  337. int
  338. OS_process_foregroundable_p (Tprocess process)
  339. {
  340.   return (0);
  341. }
  342.  
  343. pid_t
  344. OS_process_id (Tprocess process)
  345. {
  346.   return (PROCESS_ID (process));
  347. }
  348.  
  349. enum process_jc_status
  350. OS_process_jc_status (Tprocess process)
  351. {
  352.   return (process_jc_status_no_ctty);
  353. }
  354.  
  355. int
  356. OS_process_status_sync (Tprocess process)
  357. {
  358.   transaction_begin ();
  359.   lock_process_status ();
  360.   {
  361.     int result = ((PROCESS_TICK (process)) != (PROCESS_SYNC_TICK (process)));
  362.     if (result)
  363.       PROCESS_STATUS_SYNC (process);
  364.     transaction_commit ();
  365.     return (result);
  366.   }
  367. }
  368.  
  369. int
  370. OS_process_status_sync_all (void)
  371. {
  372.   transaction_begin ();
  373.   lock_process_status ();
  374.   {
  375.     int result = (process_tick != sync_tick);
  376.     if (result)
  377.       sync_tick = process_tick;
  378.     transaction_commit ();
  379.     return (result);
  380.   }
  381. }
  382.  
  383. int
  384. OS_process_any_status_change (void)
  385. {
  386.   return (process_tick != sync_tick);
  387. }
  388.  
  389. enum process_status
  390. OS_process_status (Tprocess process)
  391. {
  392.   return (PROCESS_STATUS (process));
  393. }
  394.  
  395. unsigned short
  396. OS_process_reason (Tprocess process)
  397. {
  398.   return (PROCESS_REASON (process));
  399. }
  400.  
  401. void
  402. OS_process_send_signal (Tprocess process, int sig)
  403. {
  404.   OS2_error_unimplemented_primitive ();
  405. }
  406.  
  407. void
  408. OS_process_kill (Tprocess process)
  409. {
  410.   XTD_API_CALL
  411.     (dos_kill_process, (DKP_PROCESSTREE, (PROCESS_ID (process))),
  412.      {
  413.        if (rc == ERROR_ZOMBIE_PROCESS)
  414.      return;
  415.      });
  416. }
  417.  
  418. void
  419. OS_process_stop (Tprocess process)
  420. {
  421.   OS2_error_unimplemented_primitive ();
  422. }
  423.  
  424. void
  425. OS_process_interrupt (Tprocess process)
  426. {
  427.   STD_API_CALL
  428.     (dos_send_signal_exception, ((PROCESS_ID (process)), XCPT_SIGNAL_INTR));
  429. }
  430.  
  431. void
  432. OS_process_quit (Tprocess process)
  433. {
  434.   STD_API_CALL
  435.     (dos_send_signal_exception, ((PROCESS_ID (process)), XCPT_SIGNAL_BREAK));
  436. }
  437.  
  438. void
  439. OS_process_hangup (Tprocess process)
  440. {
  441.   /* Edwin assumes that this primitive works.  Under unix, the default
  442.      behavior of SIGHUP is to kill the process, so we will emulate
  443.      SIGHUP by killing the process.  */
  444.   OS_process_kill (process);
  445. }
  446.  
  447. void
  448. OS_process_continue_background (Tprocess process)
  449. {
  450.   /* A no-op, this should only be called when OS_process_continuable_p
  451.      is true, i.e. when the process is already running.  */
  452. }
  453.  
  454. void
  455. OS_process_continue_foreground (Tprocess process)
  456. {
  457.   OS2_error_unimplemented_primitive ();
  458. }
  459.  
  460. void
  461. OS_process_wait (Tprocess process)
  462. {
  463.   while (((PROCESS_RAW_STATUS (process)) == process_status_running)
  464.      && ((OS2_message_availablep (child_wait_qid_reader, 1))
  465.          != mat_interrupt))
  466.     {
  467.       msg_t * message = (OS2_receive_message (child_wait_qid_reader, 1, 0));
  468.       PID pid = (SM_CHILD_DEATH_PID (message));
  469.       OS2_destroy_message (message);
  470.       if (pid == (PROCESS_ID (process)))
  471.     break;
  472.     }
  473. }
  474.  
  475. static void
  476. child_wait_thread (void * arg)
  477. {
  478.   EXCEPTIONREGISTRATIONRECORD registration;
  479.   (void) OS2_thread_initialize ((®istration), QID_NONE);
  480.  main_loop:
  481.   (void) OS2_wait_event_semaphore (start_child_event, 1);
  482.   (void) OS2_reset_event_semaphore (start_child_event);
  483.   while (1)
  484.     {
  485.       RESULTCODES codes;
  486.       PID pid;
  487.       Tprocess process;
  488.       XTD_API_CALL
  489.     (dos_wait_child, (DCWA_PROCESS, DCWW_WAIT, (& codes), (& pid), 0),
  490.      {
  491.        if (rc == ERROR_WAIT_NO_CHILDREN)
  492.          goto main_loop;
  493.      });
  494.       OS2_request_mutex_semaphore (process_lock);
  495.       process = (find_process (pid));
  496.       if (process == NO_PROCESS)
  497.     OS2_release_mutex_semaphore (process_lock);
  498.       else
  499.     {
  500.       if ((codes . codeTerminate) == TC_EXIT)
  501.         {
  502.           (PROCESS_RAW_STATUS (process)) = process_status_exited;
  503.           (PROCESS_RAW_REASON (process)) = (codes . codeResult);
  504.         }
  505.       else
  506.         {
  507.           (PROCESS_RAW_STATUS (process)) = process_status_signalled;
  508.           (PROCESS_RAW_REASON (process)) = 0;
  509.         }
  510.       (PROCESS_TICK (process)) = (++process_tick);
  511.       OS2_release_mutex_semaphore (process_lock);
  512.       {
  513.         msg_t * message = (OS2_create_message (mt_child_death));
  514.         (SM_CHILD_DEATH_PID (message)) = pid;
  515.         OS2_send_message (child_wait_qid_writer, message);
  516.       }
  517.     }
  518.     }
  519. }
  520.  
  521. static Tprocess
  522. find_process (PID pid)
  523. {
  524.   Tprocess process;
  525.   for (process = 0; (process < OS_process_table_size); process += 1)
  526.     if ((PROCESS_ID (process)) == pid)
  527.       return (process);
  528.   return (NO_PROCESS);
  529. }
  530.  
  531. /* OBSOLETE */
  532.  
  533. static const char * rewrite_arguments (const char **);
  534. static const char * rewrite_environment (const char **);
  535.  
  536. Tprocess
  537. OS_make_subprocess (const char * filename,
  538.             const char ** argv,
  539.             const char ** envp,
  540.             const char * working_directory,
  541.             enum process_ctty_type ctty_type,
  542.             char * ctty_name,
  543.             enum process_channel_type channel_in_type,
  544.             Tchannel channel_in,
  545.             enum process_channel_type channel_out_type,
  546.             Tchannel channel_out,
  547.             enum process_channel_type channel_err_type,
  548.             Tchannel channel_err)
  549. {
  550.   if ((ctty_type != process_ctty_type_none)
  551.       || (channel_in_type == process_channel_type_ctty)
  552.       || (channel_out_type == process_channel_type_ctty)
  553.       || (channel_err_type == process_channel_type_ctty))
  554.     OS2_error_anonymous ();
  555.   return (OS2_make_subprocess (filename,
  556.                    (rewrite_arguments (argv)),
  557.                    (rewrite_environment (envp)),
  558.                    working_directory,
  559.                    channel_in_type, channel_in,
  560.                    channel_out_type, channel_out,
  561.                    channel_err_type, channel_err));
  562. }
  563.  
  564. static const char *
  565. rewrite_arguments (const char ** argv)
  566. {
  567.   unsigned long nargs = 0;
  568.   unsigned long length = 0;
  569.   while ((argv [nargs]) != 0)
  570.     {
  571.       length += (strlen (argv [nargs]));
  572.       nargs += 1;
  573.     }
  574.   {
  575.     char * result = (dstack_alloc (length + ((nargs < 2) ? 2 : nargs) + 1));
  576.     char * scan_result = result;
  577.     if (nargs == 0)
  578.       (*scan_result++) = '\0';
  579.     else
  580.       {
  581.     unsigned long limit = (nargs - 1);
  582.     unsigned long index = 0;
  583.     while (1)
  584.       {
  585.         const char * arg = (argv [index]);
  586.         while (1)
  587.           {
  588.         char c = (*arg++);
  589.         if (c == '\0')
  590.           break;
  591.         (*scan_result++) = c;
  592.           }
  593.         if (index == limit)
  594.           break;
  595.         (*scan_result++) = ((index == 0) ? '\0' : ' ');
  596.         index += 1;
  597.       }
  598.       }
  599.     (*scan_result++) = '\0';
  600.     (*scan_result) = '\0';
  601.     return (result);
  602.   }
  603. }
  604.  
  605. static const char *
  606. rewrite_environment (const char ** envp)
  607. {
  608.   unsigned long length = 0;
  609.   const char ** scan_env = envp;
  610.   const char * binding;
  611.   char * result;
  612.   char * scan_result;
  613.  
  614.   if (envp == 0)
  615.     return (0);
  616.   while ((binding = (*scan_env++)) != 0)
  617.     length += ((strlen (binding)) + 1);
  618.   result = (dstack_alloc (length + 1));
  619.   scan_result = result;
  620.   scan_env = envp;
  621.   while ((binding = (*scan_env++)) != 0)
  622.     while (((*scan_result++) = (*binding++)) != '\0')
  623.       ;
  624.   (*scan_result) = '\0';
  625.   return (result);
  626. }
  627.