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 >
Wrap
C/C++ Source or Header
|
1999-01-02
|
18KB
|
650 lines
/* -*-C-*-
$Id: ntproc.c,v 1.8 1999/01/02 06:11:34 cph Exp $
Copyright (c) 1997-1999 Massachusetts Institute of Technology
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at
your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "nt.h"
#include "ntproc.h"
#include "ntio.h"
#include "ntscreen.h"
#include "ntgui.h"
extern const char * OS_working_dir_pathname (void);
typedef struct
{
PROCESS_INFORMATION handles;
unsigned long tick;
unsigned long sync_tick;
DWORD raw_reason;
DWORD reason;
enum process_status raw_status;
enum process_status status;
} process_t;
#define _PROCESS(process) (process_table [(process)])
#define PROCESS_HANDLES(process) ((_PROCESS(process)) . handles)
#define PROCESS_TICK(process) ((_PROCESS(process)) . tick)
#define PROCESS_SYNC_TICK(process) ((_PROCESS(process)) . sync_tick)
#define PROCESS_RAW_REASON(process) ((_PROCESS(process)) . raw_reason)
#define PROCESS_REASON(process) ((_PROCESS(process)) . reason)
#define PROCESS_RAW_STATUS(process) ((_PROCESS(process)) . raw_status)
#define PROCESS_STATUS(process) ((_PROCESS(process)) . status)
#define PROCESS_HANDLE(process) ((PROCESS_HANDLES (process)) . hProcess)
#define PROCESS_ID(process) ((PROCESS_HANDLES (process)) . dwProcessId)
#ifndef NT_DEFAULT_PROCESS_TABLE_SIZE
#define NT_DEFAULT_PROCESS_TABLE_SIZE 4096
#endif
size_t OS_process_table_size;
enum process_jc_status scheme_jc_status;
static process_t * process_table;
static unsigned long process_tick;
static unsigned long sync_tick;
#undef USE_PROCESS_TABLE_LOCK
#ifdef USE_PROCESS_TABLE_LOCK
static CRITICAL_SECTION process_table_lock;
#define GRAB_PROCESS_TABLE() EnterCriticalSection (&process_table_lock)
#define RELEASE_PROCESS_TABLE() LeaveCriticalSection (&process_table_lock)
#else
#define GRAB_PROCESS_TABLE()
#define RELEASE_PROCESS_TABLE()
#endif
#define PROCESS_STATUS_SYNC(process) \
{ \
(PROCESS_STATUS (process)) = (PROCESS_RAW_STATUS (process)); \
(PROCESS_REASON (process)) = (PROCESS_RAW_REASON (process)); \
(PROCESS_SYNC_TICK (process)) = (PROCESS_TICK (process)); \
}
/* I have no idea what a good value for this might be, so I've picked
a random non-zero value. */
#define TERMINATE_PROCESS_EXIT_CODE 0xFF
#undef TRACE_NTPROC
#ifdef TRACE_NTPROC
FILE * trace_file;
#ifndef TRACE_NTPROC_FILENAME
#define TRACE_NTPROC_FILENAME "nttrace.out"
#endif
#endif
static void lock_process_table (void);
static void lock_process_table_1 (void *);
static HANDLE stdio_handle (DWORD, Tchannel, enum process_channel_type);
static HANDLE copy_handle (HANDLE);
static Tprocess allocate_process (void);
static void allocate_process_abort (void *);
static HWND find_child_console (DWORD);
static BOOL CALLBACK find_child_console_1 (HWND, LPARAM);
static void process_wait_1 (Tprocess, DWORD);
static void process_death (Tprocess);
void
NT_initialize_processes (void)
{
#ifdef TRACE_NTPROC
trace_file = (fopen (TRACE_NTPROC_FILENAME, "w"));
#endif
OS_process_table_size = NT_DEFAULT_PROCESS_TABLE_SIZE;
process_table = (OS_malloc (OS_process_table_size * (sizeof (process_t))));
{
Tprocess process;
for (process = 0; (process < OS_process_table_size); process += 1)
OS_process_deallocate (process);
}
#ifdef USE_PROCESS_TABLE_LOCK
InitializeCriticalSection (&process_table_lock);
#endif
scheme_jc_status = process_jc_status_no_ctty;
process_tick = 0;
sync_tick = 0;
}
static void
lock_process_table (void)
{
GRAB_PROCESS_TABLE ();
transaction_record_action (tat_always, lock_process_table_1, 0);
}
static void
lock_process_table_1 (void * ignore)
{
RELEASE_PROCESS_TABLE ();
}
Tprocess
NT_make_subprocess (const char * filename,
const char * command_line,
const char * environment,
const char * working_directory,
enum process_channel_type channel_in_type,
Tchannel channel_in,
enum process_channel_type channel_out_type,
Tchannel channel_out,
enum process_channel_type channel_err_type,
Tchannel channel_err,
int hide_windows_p)
{
Tprocess child;
SECURITY_ATTRIBUTES sap;
SECURITY_DESCRIPTOR sdp;
STARTUPINFO si;
transaction_begin ();
/* Explicitly specify no security */
STD_BOOL_API_CALL
(InitializeSecurityDescriptor, ((&sdp), SECURITY_DESCRIPTOR_REVISION));
STD_BOOL_API_CALL (SetSecurityDescriptorDacl, ((&sdp), TRUE, 0, FALSE));
(sap . nLength) = (sizeof (sap));
(sap . lpSecurityDescriptor) = (&sdp);
(sap . bInheritHandle) = FALSE;
memset ((&si), 0, (sizeof (si)));
(si . cb) = (sizeof (si));
/* Specify the handles to be used by the child process. */
(si . dwFlags) = STARTF_USESTDHANDLES;
(si . hStdInput)
= (stdio_handle (STD_INPUT_HANDLE, channel_in, channel_in_type));
(si . hStdOutput)
= (stdio_handle (STD_OUTPUT_HANDLE, channel_out, channel_out_type));
(si . hStdError)
= (stdio_handle (STD_ERROR_HANDLE, channel_err, channel_err_type));
/* If requested, hide the top-level window of the child process. */
if (hide_windows_p)
{
(si . dwFlags) |= STARTF_USESHOWWINDOW;
(si . wShowWindow) |= SW_HIDE;
}
lock_process_table ();
child = (allocate_process ());
STD_BOOL_API_CALL
(CreateProcess,
(((LPCTSTR) filename),
((LPSTR) command_line),
(&sap),
0,
TRUE,
(CREATE_DEFAULT_ERROR_MODE | CREATE_NEW_CONSOLE),
((LPVOID) environment),
((LPCTSTR) working_directory),
(&si),
(& (PROCESS_HANDLES (child)))));
(PROCESS_RAW_STATUS (child)) = process_status_running;
(PROCESS_RAW_REASON (child)) = STILL_ACTIVE;
(PROCESS_TICK (child)) = process_tick;
PROCESS_STATUS_SYNC (child);
STD_BOOL_API_CALL (CloseHandle, (si . hStdInput));
STD_BOOL_API_CALL (CloseHandle, (si . hStdOutput));
STD_BOOL_API_CALL (CloseHandle, (si . hStdError));
transaction_commit ();
STD_BOOL_API_CALL (CloseHandle, ((PROCESS_HANDLES (child)) . hThread));
((PROCESS_HANDLES (child)) . hThread) = INVALID_HANDLE_VALUE;
#ifdef TRACE_NTPROC
fprintf (trace_file, "Subprocess created: id=0x%x\n", (PROCESS_ID (child)));
fflush (trace_file);
#endif
return (child);
}
static HANDLE
stdio_handle (DWORD target, Tchannel channel, enum process_channel_type type)
{
return
(copy_handle ((type == process_channel_type_explicit)
? (CHANNEL_HANDLE (channel))
: (GetStdHandle (target))));
}
static HANDLE
copy_handle (HANDLE handle)
{
HANDLE parent = (GetCurrentProcess ());
HANDLE copy;
STD_BOOL_API_CALL
(DuplicateHandle,
(parent, handle, parent, (©), 0, TRUE, DUPLICATE_SAME_ACCESS));
NT_handle_close_on_abort (copy);
return (copy);
}
static Tprocess
allocate_process (void)
{
unsigned int process;
for (process = 0; (process < OS_process_table_size); process += 1)
if ((PROCESS_RAW_STATUS (process)) == process_status_free)
{
Tprocess * pp = (dstack_alloc (sizeof (Tprocess)));
(*pp) = process;
transaction_record_action (tat_abort, allocate_process_abort, pp);
(PROCESS_RAW_STATUS (process)) = process_status_allocated;
return (process);
}
error_out_of_processes ();
return (NO_PROCESS);
}
static void
allocate_process_abort (void * environment)
{
Tprocess process = (* ((Tprocess *) environment));
OS_process_deallocate (process);
}
struct fcc_info
{
DWORD pid;
HWND hwnd;
};
static HWND
find_child_console (DWORD pid)
{
struct fcc_info fi;
(fi . pid) = pid;
(fi . hwnd) = INVALID_HANDLE_VALUE;
EnumWindows (find_child_console_1, ((LPARAM) (&fi)));
return (fi . hwnd);
}
static BOOL CALLBACK
find_child_console_1 (HWND hwnd, LPARAM lfi)
{
struct fcc_info * fi = ((struct fcc_info *) lfi);
DWORD pid;
(void) GetWindowThreadProcessId (hwnd, (&pid));
if (pid == (fi -> pid))
{
char window_class [32];
unsigned int n
= (GetClassName (hwnd, window_class, (sizeof (window_class))));
const char * console_class
= ((NT_windows_type == wintype_95) ? "tty" : "ConsoleWindowClass");
if ((n == (strlen (console_class)))
&& ((strcmp (window_class, console_class)) == 0))
{
(fi -> hwnd) = hwnd;
return (FALSE);
}
}
/* keep looking */
return (TRUE);
}
void
OS_process_deallocate (Tprocess process)
{
(PROCESS_RAW_STATUS (process)) = process_status_free;
}
int
OS_process_valid_p (Tprocess process)
{
switch (PROCESS_RAW_STATUS (process))
{
case process_status_exited:
case process_status_signalled:
case process_status_running:
return (1);
default:
return (0);
}
}
int
OS_process_continuable_p (Tprocess process)
{
return ((PROCESS_RAW_STATUS (process)) == process_status_running);
}
int
OS_process_foregroundable_p (Tprocess process)
{
return (0);
}
pid_t
OS_process_id (Tprocess process)
{
return (PROCESS_ID (process));
}
enum process_jc_status
OS_process_jc_status (Tprocess process)
{
return (process_jc_status_no_ctty);
}
int
OS_process_status_sync (Tprocess process)
{
#ifdef TRACE_NTPROC
fprintf (trace_file, "OS_process_status_sync: id=0x%x\n",
(PROCESS_ID (process)));
fflush (trace_file);
#endif
transaction_begin ();
lock_process_table ();
{
int result = ((PROCESS_TICK (process)) != (PROCESS_SYNC_TICK (process)));
if (result)
{
#ifdef TRACE_NTPROC
fprintf (trace_file, "(status=0x%x raw_status=0x%x)\n",
(PROCESS_STATUS (process)),
(PROCESS_RAW_STATUS (process)));
fflush (trace_file);
#endif
PROCESS_STATUS_SYNC (process);
}
transaction_commit ();
return (result);
}
}
int
OS_process_status_sync_all (void)
{
#ifdef TRACE_NTPROC
fprintf (trace_file, "OS_process_status_sync_all\n");
fflush (trace_file);
#endif
transaction_begin ();
lock_process_table ();
{
int result = (process_tick != sync_tick);
if (result)
{
#ifdef TRACE_NTPROC
fprintf (trace_file, "(status change)\n");
fflush (trace_file);
#endif
sync_tick = process_tick;
}
transaction_commit ();
return (result);
}
}
enum process_status
OS_process_status (Tprocess process)
{
#ifdef TRACE_NTPROC
fprintf (trace_file, "OS_process_status: id=0x%x status=0x%x\n",
(PROCESS_ID (process)),
(PROCESS_STATUS (process)));
fflush (trace_file);
#endif
return (PROCESS_STATUS (process));
}
unsigned short
OS_process_reason (Tprocess process)
{
return ((unsigned short) (PROCESS_REASON (process)));
}
void
OS_process_send_signal (Tprocess process, int sig)
{
error_unimplemented_primitive ();
}
void
OS_process_kill (Tprocess process)
{
#ifdef TRACE_NTPROC
fprintf (trace_file, "OS_process_kill: id=0x%x\n", (PROCESS_ID (process)));
fflush (trace_file);
#endif
if (NT_windows_type == wintype_nt)
{
HWND hwnd = (find_child_console (PROCESS_ID (process)));
if (hwnd != INVALID_HANDLE_VALUE)
{
PostMessage (hwnd, WM_CLOSE, 0, 0);
return;
}
}
#ifdef TRACE_NTPROC
fprintf (trace_file, "(using TerminateProcess)\n");
fflush (trace_file);
#endif
if (!TerminateProcess ((PROCESS_HANDLE (process)),
TERMINATE_PROCESS_EXIT_CODE))
{
DWORD code = (GetLastError ());
if (code != ERROR_ACCESS_DENIED)
NT_error_api_call ((GetLastError ()), apicall_TerminateProcess);
#ifdef TRACE_NTPROC
fprintf (trace_file, "(ERROR_ACCESS_DENIED)\n");
fflush (trace_file);
#endif
}
}
void
OS_process_stop (Tprocess process)
{
error_unimplemented_primitive ();
}
void
OS_process_interrupt (Tprocess process)
{
HWND hwnd;
BYTE control_scan_code;
BYTE vk_break_code;
BYTE break_scan_code;
/* BYTE keyboard_state [256]; */
HWND foreground_window;
#ifdef TRACE_NTPROC
fprintf (trace_file, "OS_process_interrupt: id=0x%x\n",
(PROCESS_ID (process)));
fflush (trace_file);
#endif
hwnd = (find_child_console (PROCESS_ID (process)));
if (hwnd == INVALID_HANDLE_VALUE)
return;
control_scan_code = ((BYTE) (MapVirtualKey (VK_CONTROL, 0)));
vk_break_code = VK_CANCEL;
break_scan_code = ((BYTE) (MapVirtualKey (vk_break_code, 0)));
if (break_scan_code == 0)
{
/* Fake Ctrl-C if we can't manage Ctrl-Break. */
vk_break_code = 'C';
break_scan_code = ((BYTE) (MapVirtualKey (vk_break_code, 0)));
}
/* STD_BOOL_API_CALL (GetKeyboardState, (keyboard_state)); */
foreground_window = (GetForegroundWindow ());
if (SetForegroundWindow (hwnd))
{
/* Generate keystrokes as if user had typed Ctrl-Break or Ctrl-C. */
keybd_event (VK_CONTROL, control_scan_code, 0, 0);
keybd_event (vk_break_code, break_scan_code, 0, 0);
keybd_event (vk_break_code, break_scan_code, KEYEVENTF_KEYUP, 0);
keybd_event (VK_CONTROL, control_scan_code, KEYEVENTF_KEYUP, 0);
if (foreground_window)
(void) SetForegroundWindow (foreground_window);
}
/* STD_BOOL_API_CALL (SetKeyboardState, (keyboard_state)); */
}
void
OS_process_quit (Tprocess process)
{
error_unimplemented_primitive ();
}
void
OS_process_hangup (Tprocess process)
{
/* Edwin assumes that this primitive works. Under unix, the default
behavior of SIGHUP is to kill the process, so we will emulate
SIGHUP by killing the process. */
OS_process_kill (process);
}
void
OS_process_continue_background (Tprocess process)
{
/* A no-op, this should only be called when OS_process_continuable_p
is true, i.e. when the process is already running. */
}
void
OS_process_continue_foreground (Tprocess process)
{
error_unimplemented_primitive ();
}
#ifndef WIN32_WAIT_INTERVAL
#define WIN32_WAIT_INTERVAL 50
#endif
void
OS_process_wait (Tprocess process)
{
process_wait_1 (process, 0);
while (1)
{
if (((PROCESS_RAW_STATUS (process)) != process_status_running)
|| (pending_interrupts_p ()))
break;
process_wait_1 (process, WIN32_WAIT_INTERVAL);
}
}
static void
process_wait_1 (Tprocess process, DWORD interval)
{
#ifdef TRACE_NTPROC
fprintf (trace_file, "process_wait_1: id=0x%x raw_status=0x%x\n",
(PROCESS_ID (process)),
(PROCESS_RAW_STATUS (process)));
fflush (trace_file);
#endif
if ((PROCESS_RAW_STATUS (process)) == process_status_running)
{
DWORD code
= (MsgWaitForMultipleObjects (1,
(& (PROCESS_HANDLE (process))),
FALSE,
interval,
QS_ALLINPUT));
#ifdef TRACE_NTPROC
fprintf (trace_file, "(wait result = 0x%x)\n", code);
fflush (trace_file);
#endif
switch (code)
{
case WAIT_OBJECT_0:
process_death (process);
break;
case WAIT_FAILED:
NT_error_api_call ((GetLastError ()),
apicall_MsgWaitForMultipleObjects);
break;
}
}
}
int
OS_process_any_status_change (void)
{
Tprocess process;
#ifdef TRACE_NTPROC
fprintf (trace_file, "OS_process_any_status_change\n");
fflush (trace_file);
#endif
for (process = 0; (process < OS_process_table_size); process += 1)
if ((PROCESS_RAW_STATUS (process)) == process_status_running)
switch (WaitForSingleObject ((PROCESS_HANDLE (process)), 0))
{
case WAIT_OBJECT_0:
process_death (process);
break;
case WAIT_FAILED:
NT_error_api_call ((GetLastError ()),
apicall_MsgWaitForMultipleObjects);
break;
}
#ifdef TRACE_NTPROC
if (process_tick != sync_tick)
{
fprintf (trace_file, "(status change)\n");
fflush (trace_file);
}
#endif
return (process_tick != sync_tick);
}
static void
process_death (Tprocess process)
{
DWORD exit_code;
#ifdef TRACE_NTPROC
fprintf (trace_file, "process_death: id=0x%x\n", (PROCESS_ID (process)));
fflush (trace_file);
#endif
STD_BOOL_API_CALL
(GetExitCodeProcess, ((PROCESS_HANDLE (process)), (&exit_code)));
#ifdef TRACE_NTPROC
fprintf (trace_file, "(exit_code = 0x%x)\n", exit_code);
fflush (trace_file);
#endif
GRAB_PROCESS_TABLE ();
(PROCESS_RAW_STATUS (process))
= ((exit_code == STATUS_CONTROL_C_EXIT)
? process_status_signalled
: process_status_exited);
(PROCESS_RAW_REASON (process)) = exit_code;
(PROCESS_TICK (process)) = (++process_tick);
STD_BOOL_API_CALL (CloseHandle, (PROCESS_HANDLE (process)));
(PROCESS_HANDLE (process)) = INVALID_HANDLE_VALUE;
RELEASE_PROCESS_TABLE ();
}
Tprocess
OS_make_subprocess (const char * filename,
const char ** argv,
const char ** envp,
const char * working_directory,
enum process_ctty_type ctty_type,
char * ctty_name,
enum process_channel_type channel_in_type,
Tchannel channel_in,
enum process_channel_type channel_out_type,
Tchannel channel_out,
enum process_channel_type channel_err_type,
Tchannel channel_err)
{
error_unimplemented_primitive ();
return (NO_PROCESS);
}