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 / ntproc.c < prev    next >
C/C++ Source or Header  |  1999-01-02  |  18KB  |  650 lines

  1. /* -*-C-*-
  2.  
  3. $Id: ntproc.c,v 1.8 1999/01/02 06:11:34 cph Exp $
  4.  
  5. Copyright (c) 1997-1999 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 "nt.h"
  23. #include "ntproc.h"
  24. #include "ntio.h"
  25. #include "ntscreen.h"
  26. #include "ntgui.h"
  27.  
  28. extern const char * OS_working_dir_pathname (void);
  29.  
  30. typedef struct
  31. {
  32.   PROCESS_INFORMATION handles;
  33.   unsigned long tick;
  34.   unsigned long sync_tick;
  35.   DWORD raw_reason;
  36.   DWORD reason;
  37.   enum process_status raw_status;
  38.   enum process_status status;
  39. } process_t;
  40. #define _PROCESS(process) (process_table [(process)])
  41. #define PROCESS_HANDLES(process) ((_PROCESS(process)) . handles)
  42. #define PROCESS_TICK(process) ((_PROCESS(process)) . tick)
  43. #define PROCESS_SYNC_TICK(process) ((_PROCESS(process)) . sync_tick)
  44. #define PROCESS_RAW_REASON(process) ((_PROCESS(process)) . raw_reason)
  45. #define PROCESS_REASON(process) ((_PROCESS(process)) . reason)
  46. #define PROCESS_RAW_STATUS(process) ((_PROCESS(process)) . raw_status)
  47. #define PROCESS_STATUS(process) ((_PROCESS(process)) . status)
  48.  
  49. #define PROCESS_HANDLE(process) ((PROCESS_HANDLES (process)) . hProcess)
  50. #define PROCESS_ID(process) ((PROCESS_HANDLES (process)) . dwProcessId)
  51.  
  52. #ifndef NT_DEFAULT_PROCESS_TABLE_SIZE
  53. #define NT_DEFAULT_PROCESS_TABLE_SIZE 4096
  54. #endif
  55. size_t OS_process_table_size;
  56. enum process_jc_status scheme_jc_status;
  57.  
  58. static process_t * process_table;
  59. static unsigned long process_tick;
  60. static unsigned long sync_tick;
  61.  
  62. #undef USE_PROCESS_TABLE_LOCK
  63. #ifdef USE_PROCESS_TABLE_LOCK
  64. static CRITICAL_SECTION process_table_lock;
  65. #define GRAB_PROCESS_TABLE() EnterCriticalSection (&process_table_lock)
  66. #define RELEASE_PROCESS_TABLE() LeaveCriticalSection (&process_table_lock)
  67. #else
  68. #define GRAB_PROCESS_TABLE()
  69. #define RELEASE_PROCESS_TABLE()
  70. #endif
  71.  
  72. #define PROCESS_STATUS_SYNC(process)                    \
  73. {                                    \
  74.   (PROCESS_STATUS (process)) = (PROCESS_RAW_STATUS (process));        \
  75.   (PROCESS_REASON (process)) = (PROCESS_RAW_REASON (process));        \
  76.   (PROCESS_SYNC_TICK (process)) = (PROCESS_TICK (process));        \
  77. }
  78.  
  79. /* I have no idea what a good value for this might be, so I've picked
  80.    a random non-zero value.  */
  81. #define TERMINATE_PROCESS_EXIT_CODE 0xFF
  82.  
  83. #undef TRACE_NTPROC
  84. #ifdef TRACE_NTPROC
  85. FILE * trace_file;
  86. #ifndef TRACE_NTPROC_FILENAME
  87. #define TRACE_NTPROC_FILENAME "nttrace.out"
  88. #endif
  89. #endif
  90.  
  91. static void lock_process_table (void);
  92. static void lock_process_table_1 (void *);
  93. static HANDLE stdio_handle (DWORD, Tchannel, enum process_channel_type);
  94. static HANDLE copy_handle (HANDLE);
  95. static Tprocess allocate_process (void);
  96. static void allocate_process_abort (void *);
  97. static HWND find_child_console (DWORD);
  98. static BOOL CALLBACK find_child_console_1 (HWND, LPARAM);
  99. static void process_wait_1 (Tprocess, DWORD);
  100. static void process_death (Tprocess);
  101.  
  102. void
  103. NT_initialize_processes (void)
  104. {
  105. #ifdef TRACE_NTPROC
  106.   trace_file = (fopen (TRACE_NTPROC_FILENAME, "w"));
  107. #endif
  108.   OS_process_table_size = NT_DEFAULT_PROCESS_TABLE_SIZE;
  109.   process_table = (OS_malloc (OS_process_table_size * (sizeof (process_t))));
  110.   {
  111.     Tprocess process;
  112.     for (process = 0; (process < OS_process_table_size); process += 1)
  113.       OS_process_deallocate (process);
  114.   }
  115. #ifdef USE_PROCESS_TABLE_LOCK
  116.   InitializeCriticalSection (&process_table_lock);
  117. #endif
  118.   scheme_jc_status = process_jc_status_no_ctty;
  119.   process_tick = 0;
  120.   sync_tick = 0;
  121. }
  122.  
  123. static void
  124. lock_process_table (void)
  125. {
  126.   GRAB_PROCESS_TABLE ();
  127.   transaction_record_action (tat_always, lock_process_table_1, 0);
  128. }
  129.  
  130. static void
  131. lock_process_table_1 (void * ignore)
  132. {
  133.   RELEASE_PROCESS_TABLE ();
  134. }
  135.  
  136. Tprocess
  137. NT_make_subprocess (const char * filename,
  138.             const char * command_line,
  139.             const char * environment,
  140.             const char * working_directory,
  141.             enum process_channel_type channel_in_type,
  142.             Tchannel channel_in,
  143.             enum process_channel_type channel_out_type,
  144.             Tchannel channel_out,
  145.             enum process_channel_type channel_err_type,
  146.             Tchannel channel_err,
  147.             int hide_windows_p)
  148. {
  149.   Tprocess child;
  150.   SECURITY_ATTRIBUTES sap;
  151.   SECURITY_DESCRIPTOR sdp;
  152.   STARTUPINFO si;
  153.  
  154.   transaction_begin ();
  155.  
  156.   /* Explicitly specify no security */
  157.   STD_BOOL_API_CALL
  158.     (InitializeSecurityDescriptor, ((&sdp), SECURITY_DESCRIPTOR_REVISION));
  159.   STD_BOOL_API_CALL (SetSecurityDescriptorDacl, ((&sdp), TRUE, 0, FALSE));
  160.   (sap . nLength) = (sizeof (sap));
  161.   (sap . lpSecurityDescriptor) = (&sdp);
  162.   (sap . bInheritHandle) = FALSE;
  163.  
  164.   memset ((&si), 0, (sizeof (si)));
  165.   (si . cb) = (sizeof (si));
  166.   /* Specify the handles to be used by the child process.  */
  167.   (si . dwFlags) = STARTF_USESTDHANDLES;
  168.   (si . hStdInput)
  169.     = (stdio_handle (STD_INPUT_HANDLE, channel_in, channel_in_type));
  170.   (si . hStdOutput)
  171.     = (stdio_handle (STD_OUTPUT_HANDLE, channel_out, channel_out_type));
  172.   (si . hStdError)
  173.     = (stdio_handle (STD_ERROR_HANDLE, channel_err, channel_err_type));
  174.   /* If requested, hide the top-level window of the child process.  */
  175.   if (hide_windows_p)
  176.     {
  177.       (si . dwFlags) |= STARTF_USESHOWWINDOW;
  178.       (si . wShowWindow) |= SW_HIDE;
  179.     }
  180.  
  181.   lock_process_table ();
  182.   child = (allocate_process ());
  183.   STD_BOOL_API_CALL
  184.     (CreateProcess,
  185.      (((LPCTSTR) filename),
  186.       ((LPSTR) command_line),
  187.       (&sap),
  188.       0,
  189.       TRUE,
  190.       (CREATE_DEFAULT_ERROR_MODE | CREATE_NEW_CONSOLE),
  191.       ((LPVOID) environment),
  192.       ((LPCTSTR) working_directory),
  193.       (&si),
  194.       (& (PROCESS_HANDLES (child)))));
  195.   (PROCESS_RAW_STATUS (child)) = process_status_running;
  196.   (PROCESS_RAW_REASON (child)) = STILL_ACTIVE;
  197.   (PROCESS_TICK (child)) = process_tick;
  198.   PROCESS_STATUS_SYNC (child);
  199.   STD_BOOL_API_CALL (CloseHandle, (si . hStdInput));
  200.   STD_BOOL_API_CALL (CloseHandle, (si . hStdOutput));
  201.   STD_BOOL_API_CALL (CloseHandle, (si . hStdError));
  202.   transaction_commit ();
  203.   STD_BOOL_API_CALL (CloseHandle, ((PROCESS_HANDLES (child)) . hThread));
  204.   ((PROCESS_HANDLES (child)) . hThread) = INVALID_HANDLE_VALUE;
  205. #ifdef TRACE_NTPROC
  206.   fprintf (trace_file, "Subprocess created: id=0x%x\n", (PROCESS_ID (child)));
  207.   fflush (trace_file);
  208. #endif
  209.   return (child);
  210. }
  211.  
  212. static HANDLE
  213. stdio_handle (DWORD target, Tchannel channel, enum process_channel_type type)
  214. {
  215.   return
  216.     (copy_handle ((type == process_channel_type_explicit)
  217.           ? (CHANNEL_HANDLE (channel))
  218.           : (GetStdHandle (target))));
  219. }
  220.  
  221. static HANDLE
  222. copy_handle (HANDLE handle)
  223. {
  224.   HANDLE parent = (GetCurrentProcess ());
  225.   HANDLE copy;
  226.   STD_BOOL_API_CALL
  227.     (DuplicateHandle,
  228.      (parent, handle, parent, (©), 0, TRUE, DUPLICATE_SAME_ACCESS));
  229.   NT_handle_close_on_abort (copy);
  230.   return (copy);
  231. }
  232.  
  233. static Tprocess
  234. allocate_process (void)
  235. {
  236.   unsigned int process;
  237.   for (process = 0; (process < OS_process_table_size); process += 1)
  238.     if ((PROCESS_RAW_STATUS (process)) == process_status_free)
  239.       {
  240.     Tprocess * pp = (dstack_alloc (sizeof (Tprocess)));
  241.     (*pp) = process;
  242.     transaction_record_action (tat_abort, allocate_process_abort, pp);
  243.     (PROCESS_RAW_STATUS (process)) = process_status_allocated;
  244.     return (process);
  245.       }
  246.   error_out_of_processes ();
  247.   return (NO_PROCESS);
  248. }
  249.  
  250. static void
  251. allocate_process_abort (void * environment)
  252. {
  253.   Tprocess process = (* ((Tprocess *) environment));
  254.   OS_process_deallocate (process);
  255. }
  256.  
  257. struct fcc_info
  258. {
  259.   DWORD pid;
  260.   HWND hwnd;
  261. };
  262.  
  263. static HWND
  264. find_child_console (DWORD pid)
  265. {
  266.   struct fcc_info fi;
  267.   (fi . pid) = pid;
  268.   (fi . hwnd) = INVALID_HANDLE_VALUE;
  269.   EnumWindows (find_child_console_1, ((LPARAM) (&fi)));
  270.   return (fi . hwnd);
  271. }
  272.  
  273. static BOOL CALLBACK
  274. find_child_console_1 (HWND hwnd, LPARAM lfi)
  275. {
  276.   struct fcc_info * fi = ((struct fcc_info *) lfi);
  277.   DWORD pid;
  278.  
  279.   (void) GetWindowThreadProcessId (hwnd, (&pid));
  280.   if (pid == (fi -> pid))
  281.     {
  282.       char window_class [32];
  283.       unsigned int n
  284.     = (GetClassName (hwnd, window_class, (sizeof (window_class))));
  285.       const char * console_class
  286.     = ((NT_windows_type == wintype_95) ? "tty" : "ConsoleWindowClass");
  287.       if ((n == (strlen (console_class)))
  288.       && ((strcmp (window_class, console_class)) == 0))
  289.     {
  290.       (fi -> hwnd) = hwnd;
  291.       return (FALSE);
  292.     }
  293.     }
  294.   /* keep looking */
  295.   return (TRUE);
  296. }
  297.  
  298. void
  299. OS_process_deallocate (Tprocess process)
  300. {
  301.   (PROCESS_RAW_STATUS (process)) = process_status_free;
  302. }
  303.  
  304. int
  305. OS_process_valid_p (Tprocess process)
  306. {
  307.   switch (PROCESS_RAW_STATUS (process))
  308.     {
  309.     case process_status_exited:
  310.     case process_status_signalled:
  311.     case process_status_running:
  312.       return (1);
  313.     default:
  314.       return (0);
  315.     }
  316. }
  317.  
  318. int
  319. OS_process_continuable_p (Tprocess process)
  320. {
  321.   return ((PROCESS_RAW_STATUS (process)) == process_status_running);
  322. }
  323.  
  324. int
  325. OS_process_foregroundable_p (Tprocess process)
  326. {
  327.   return (0);
  328. }
  329.  
  330. pid_t
  331. OS_process_id (Tprocess process)
  332. {
  333.   return (PROCESS_ID (process));
  334. }
  335.  
  336. enum process_jc_status
  337. OS_process_jc_status (Tprocess process)
  338. {
  339.   return (process_jc_status_no_ctty);
  340. }
  341.  
  342. int
  343. OS_process_status_sync (Tprocess process)
  344. {
  345. #ifdef TRACE_NTPROC
  346.   fprintf (trace_file, "OS_process_status_sync: id=0x%x\n",
  347.        (PROCESS_ID (process)));
  348.   fflush (trace_file);
  349. #endif
  350.   transaction_begin ();
  351.   lock_process_table ();
  352.   {
  353.     int result = ((PROCESS_TICK (process)) != (PROCESS_SYNC_TICK (process)));
  354.     if (result)
  355.       {
  356. #ifdef TRACE_NTPROC
  357.     fprintf (trace_file, "(status=0x%x raw_status=0x%x)\n",
  358.          (PROCESS_STATUS (process)),
  359.          (PROCESS_RAW_STATUS (process)));
  360.     fflush (trace_file);
  361. #endif
  362.     PROCESS_STATUS_SYNC (process);
  363.       }
  364.     transaction_commit ();
  365.     return (result);
  366.   }
  367. }
  368.  
  369. int
  370. OS_process_status_sync_all (void)
  371. {
  372. #ifdef TRACE_NTPROC
  373.   fprintf (trace_file, "OS_process_status_sync_all\n");
  374.   fflush (trace_file);
  375. #endif
  376.   transaction_begin ();
  377.   lock_process_table ();
  378.   {
  379.     int result = (process_tick != sync_tick);
  380.     if (result)
  381.       {
  382. #ifdef TRACE_NTPROC
  383.     fprintf (trace_file, "(status change)\n");
  384.     fflush (trace_file);
  385. #endif
  386.     sync_tick = process_tick;
  387.       }
  388.     transaction_commit ();
  389.     return (result);
  390.   }
  391. }
  392.  
  393. enum process_status
  394. OS_process_status (Tprocess process)
  395. {
  396. #ifdef TRACE_NTPROC
  397.   fprintf (trace_file, "OS_process_status: id=0x%x status=0x%x\n",
  398.        (PROCESS_ID (process)),
  399.        (PROCESS_STATUS (process)));
  400.   fflush (trace_file);
  401. #endif
  402.   return (PROCESS_STATUS (process));
  403. }
  404.  
  405. unsigned short
  406. OS_process_reason (Tprocess process)
  407. {
  408.   return ((unsigned short) (PROCESS_REASON (process)));
  409. }
  410.  
  411. void
  412. OS_process_send_signal (Tprocess process, int sig)
  413. {
  414.   error_unimplemented_primitive ();
  415. }
  416.  
  417. void
  418. OS_process_kill (Tprocess process)
  419. {
  420. #ifdef TRACE_NTPROC
  421.   fprintf (trace_file, "OS_process_kill: id=0x%x\n", (PROCESS_ID (process)));
  422.   fflush (trace_file);
  423. #endif
  424.   if (NT_windows_type == wintype_nt)
  425.     {
  426.       HWND hwnd = (find_child_console (PROCESS_ID (process)));
  427.       if (hwnd != INVALID_HANDLE_VALUE)
  428.     {
  429.       PostMessage (hwnd, WM_CLOSE, 0, 0);
  430.       return;
  431.     }
  432.     }
  433. #ifdef TRACE_NTPROC
  434.   fprintf (trace_file, "(using TerminateProcess)\n");
  435.   fflush (trace_file);
  436. #endif
  437.   if (!TerminateProcess ((PROCESS_HANDLE (process)),
  438.              TERMINATE_PROCESS_EXIT_CODE))
  439.     {
  440.       DWORD code = (GetLastError ());
  441.       if (code != ERROR_ACCESS_DENIED)
  442.     NT_error_api_call ((GetLastError ()), apicall_TerminateProcess);
  443. #ifdef TRACE_NTPROC
  444.       fprintf (trace_file, "(ERROR_ACCESS_DENIED)\n");
  445.       fflush (trace_file);
  446. #endif
  447.     }
  448. }
  449.  
  450. void
  451. OS_process_stop (Tprocess process)
  452. {
  453.   error_unimplemented_primitive ();
  454. }
  455.  
  456. void
  457. OS_process_interrupt (Tprocess process)
  458. {
  459.   HWND hwnd;
  460.   BYTE control_scan_code;
  461.   BYTE vk_break_code;
  462.   BYTE break_scan_code;
  463.   /* BYTE keyboard_state [256]; */
  464.   HWND foreground_window;
  465.  
  466. #ifdef TRACE_NTPROC
  467.   fprintf (trace_file, "OS_process_interrupt: id=0x%x\n",
  468.        (PROCESS_ID (process)));
  469.   fflush (trace_file);
  470. #endif
  471.   hwnd = (find_child_console (PROCESS_ID (process)));
  472.   if (hwnd == INVALID_HANDLE_VALUE)
  473.     return;
  474.   control_scan_code = ((BYTE) (MapVirtualKey (VK_CONTROL, 0)));
  475.   vk_break_code = VK_CANCEL;
  476.   break_scan_code = ((BYTE) (MapVirtualKey (vk_break_code, 0)));
  477.   if (break_scan_code == 0)
  478.     {
  479.       /* Fake Ctrl-C if we can't manage Ctrl-Break. */
  480.       vk_break_code = 'C';
  481.       break_scan_code = ((BYTE) (MapVirtualKey (vk_break_code, 0)));
  482.     }
  483.   /* STD_BOOL_API_CALL (GetKeyboardState, (keyboard_state)); */
  484.   foreground_window = (GetForegroundWindow ());
  485.   if (SetForegroundWindow (hwnd))
  486.     {
  487.       /* Generate keystrokes as if user had typed Ctrl-Break or Ctrl-C.  */
  488.       keybd_event (VK_CONTROL, control_scan_code, 0, 0);
  489.       keybd_event (vk_break_code, break_scan_code, 0, 0);
  490.       keybd_event (vk_break_code, break_scan_code, KEYEVENTF_KEYUP, 0);
  491.       keybd_event (VK_CONTROL, control_scan_code, KEYEVENTF_KEYUP, 0);
  492.       if (foreground_window)
  493.     (void) SetForegroundWindow (foreground_window);
  494.     }
  495.   /* STD_BOOL_API_CALL (SetKeyboardState, (keyboard_state)); */
  496. }
  497.  
  498. void
  499. OS_process_quit (Tprocess process)
  500. {
  501.   error_unimplemented_primitive ();
  502. }
  503.  
  504. void
  505. OS_process_hangup (Tprocess process)
  506. {
  507.   /* Edwin assumes that this primitive works.  Under unix, the default
  508.      behavior of SIGHUP is to kill the process, so we will emulate
  509.      SIGHUP by killing the process.  */
  510.   OS_process_kill (process);
  511. }
  512.  
  513. void
  514. OS_process_continue_background (Tprocess process)
  515. {
  516.   /* A no-op, this should only be called when OS_process_continuable_p
  517.      is true, i.e. when the process is already running.  */
  518. }
  519.  
  520. void
  521. OS_process_continue_foreground (Tprocess process)
  522. {
  523.   error_unimplemented_primitive ();
  524. }
  525.  
  526. #ifndef WIN32_WAIT_INTERVAL
  527. #define WIN32_WAIT_INTERVAL 50
  528. #endif
  529.  
  530. void
  531. OS_process_wait (Tprocess process)
  532. {
  533.   process_wait_1 (process, 0);
  534.   while (1)
  535.     {
  536.       if (((PROCESS_RAW_STATUS (process)) != process_status_running)
  537.       || (pending_interrupts_p ()))
  538.     break;
  539.       process_wait_1 (process, WIN32_WAIT_INTERVAL);
  540.     }
  541. }
  542.  
  543. static void
  544. process_wait_1 (Tprocess process, DWORD interval)
  545. {
  546. #ifdef TRACE_NTPROC
  547.   fprintf (trace_file, "process_wait_1: id=0x%x raw_status=0x%x\n",
  548.        (PROCESS_ID (process)),
  549.        (PROCESS_RAW_STATUS (process)));
  550.   fflush (trace_file);
  551. #endif
  552.   if ((PROCESS_RAW_STATUS (process)) == process_status_running)
  553.     {
  554.       DWORD code
  555.     = (MsgWaitForMultipleObjects (1,
  556.                       (& (PROCESS_HANDLE (process))),
  557.                       FALSE,
  558.                       interval,
  559.                       QS_ALLINPUT));
  560. #ifdef TRACE_NTPROC
  561.       fprintf (trace_file, "(wait result = 0x%x)\n", code);
  562.       fflush (trace_file);
  563. #endif
  564.       switch (code)
  565.     {
  566.     case WAIT_OBJECT_0:
  567.       process_death (process);
  568.       break;
  569.     case WAIT_FAILED:
  570.       NT_error_api_call ((GetLastError ()),
  571.                  apicall_MsgWaitForMultipleObjects);
  572.       break;
  573.     }
  574.     }
  575. }
  576.  
  577. int
  578. OS_process_any_status_change (void)
  579. {
  580.   Tprocess process;
  581. #ifdef TRACE_NTPROC
  582.   fprintf (trace_file, "OS_process_any_status_change\n");
  583.   fflush (trace_file);
  584. #endif
  585.   for (process = 0; (process < OS_process_table_size); process += 1)
  586.     if ((PROCESS_RAW_STATUS (process)) == process_status_running)
  587.       switch (WaitForSingleObject ((PROCESS_HANDLE (process)), 0))
  588.     {
  589.     case WAIT_OBJECT_0:
  590.       process_death (process);
  591.       break;
  592.     case WAIT_FAILED:
  593.       NT_error_api_call ((GetLastError ()),
  594.                  apicall_MsgWaitForMultipleObjects);
  595.       break;
  596.     }
  597. #ifdef TRACE_NTPROC
  598.   if (process_tick != sync_tick)
  599.     {
  600.       fprintf (trace_file, "(status change)\n");
  601.       fflush (trace_file);
  602.     }
  603. #endif
  604.   return (process_tick != sync_tick);
  605. }
  606.  
  607. static void
  608. process_death (Tprocess process)
  609. {
  610.   DWORD exit_code;
  611. #ifdef TRACE_NTPROC
  612.   fprintf (trace_file, "process_death: id=0x%x\n", (PROCESS_ID (process)));
  613.   fflush (trace_file);
  614. #endif
  615.   STD_BOOL_API_CALL
  616.     (GetExitCodeProcess, ((PROCESS_HANDLE (process)), (&exit_code)));
  617. #ifdef TRACE_NTPROC
  618.   fprintf (trace_file, "(exit_code = 0x%x)\n", exit_code);
  619.   fflush (trace_file);
  620. #endif
  621.   GRAB_PROCESS_TABLE ();
  622.   (PROCESS_RAW_STATUS (process))
  623.     = ((exit_code == STATUS_CONTROL_C_EXIT)
  624.        ? process_status_signalled
  625.        : process_status_exited);
  626.   (PROCESS_RAW_REASON (process)) = exit_code;
  627.   (PROCESS_TICK (process)) = (++process_tick);
  628.   STD_BOOL_API_CALL (CloseHandle, (PROCESS_HANDLE (process)));
  629.   (PROCESS_HANDLE (process)) = INVALID_HANDLE_VALUE;
  630.   RELEASE_PROCESS_TABLE ();
  631. }
  632.  
  633. Tprocess
  634. OS_make_subprocess (const char * filename,
  635.             const char ** argv,
  636.             const char ** envp,
  637.             const char * working_directory,
  638.             enum process_ctty_type ctty_type,
  639.             char * ctty_name,
  640.             enum process_channel_type channel_in_type,
  641.             Tchannel channel_in,
  642.             enum process_channel_type channel_out_type,
  643.             Tchannel channel_out,
  644.             enum process_channel_type channel_err_type,
  645.             Tchannel channel_err)
  646. {
  647.   error_unimplemented_primitive ();
  648.   return (NO_PROCESS);
  649. }
  650.