/* -*-C-*- $Id: ntsig.c,v 1.22 2000/12/05 21:23:45 cph Exp $ Copyright (c) 1992-2000 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. */ /* Hacks by SRA for NT: 1. punt interactive debugging completely */ #include "scheme.h" #include "critsec.h" #include "ossig.h" #include "osctty.h" #include "ostty.h" #include "nt.h" #include "ntgui.h" #include "ntio.h" #include "ntscmlib.h" #include "ntscreen.h" #include "ntsys.h" extern HANDLE master_tty_window; /* Signal mask manipulation */ /* These could be implemented, at least under Win32s/DPMI by examining and setting the virtual interrupt state. */ void DEFUN_VOID (preserve_signal_mask) { return; } void DEFUN_VOID (block_signals) { return; } void DEFUN_VOID (unblock_signals) { return; } #define CONTROL_B_INTERRUPT_CHAR 'B' #define CONTROL_G_INTERRUPT_CHAR 'G' #define CONTROL_U_INTERRUPT_CHAR 'U' #define CONTROL_X_INTERRUPT_CHAR 'X' #define INTERACTIVE_INTERRUPT_CHAR '!' #define TERMINATE_INTERRUPT_CHAR '@' #define NO_INTERRUPT_CHAR '0' /* Keyboard interrupt */ #define KB_INT_TABLE_SIZE ((256) + 1) #define CONTROL_BREAK '\0' /* A lie. */ #define CONTROL_B '\002' #define CONTROL_C '\003' #define CONTROL_G '\007' #define CONTROL_U '\025' #define CONTROL_X '\030' #define CONTROL_B_ENABLE (0x1) #define CONTROL_G_ENABLE (0x2) #define CONTROL_U_ENABLE (0x4) #define CONTROL_X_ENABLE (0x8) #define INTERACTIVE_INTERRUPT_ENABLE (0x10) #define TERMINATE_INTERRUPT_ENABLE (0x20) /* This is a table and also a null terminated string. */ unsigned char keyboard_interrupt_table[KB_INT_TABLE_SIZE]; static unsigned char keyboard_interrupt_enables; void DEFUN (OS_ctty_get_interrupt_enables, (mask), Tinterrupt_enables * mask) { *mask = ((Tinterrupt_enables) keyboard_interrupt_enables); return; } void DEFUN (OS_ctty_set_interrupt_enables, (mask), Tinterrupt_enables * mask) { /* Kludge: ctl-break always enabled. */ keyboard_interrupt_enables = (((unsigned char) (* mask)) | TERMINATE_INTERRUPT_ENABLE); return; } /* This is a temporary kludge. */ #define NUM_INT_CHANNELS 6 static cc_t int_chars[NUM_INT_CHANNELS]; static cc_t int_handlers[NUM_INT_CHANNELS]; #define SCREEN_COMMAND_INTERRUPT_FIRST (SCREEN_COMMAND_CLOSE+10) int EXFUN (signal_keyboard_character_interrupt, (int)); LRESULT master_tty_interrupt (HWND tty, WORD command) { int ch = int_chars[command - SCREEN_COMMAND_INTERRUPT_FIRST]; return (signal_keyboard_character_interrupt (ch)); } static void DEFUN_VOID (update_interrupt_characters) { int i; for (i = 0; i < KB_INT_TABLE_SIZE; i++) { keyboard_interrupt_table[i] = NO_INTERRUPT_CHAR; SendMessage (master_tty_window, SCREEN_SETBINDING, i, 0); } for (i = 0; i < NUM_INT_CHANNELS; i++) { unsigned char handler; switch (int_handlers[i]) { case interrupt_handler_control_b: handler = CONTROL_B_INTERRUPT_CHAR; break; case interrupt_handler_control_g: handler = CONTROL_G_INTERRUPT_CHAR; break; case interrupt_handler_control_u: handler = CONTROL_U_INTERRUPT_CHAR; break; case interrupt_handler_control_x: handler = CONTROL_X_INTERRUPT_CHAR; break; case interrupt_handler_interactive: handler = INTERACTIVE_INTERRUPT_CHAR; break; case interrupt_handler_terminate: handler = TERMINATE_INTERRUPT_CHAR; break; default: handler = NO_INTERRUPT_CHAR; break; } keyboard_interrupt_table[(int) (int_chars[i])] = handler; SendMessage (master_tty_window, SCREEN_SETCOMMAND, (SCREEN_COMMAND_INTERRUPT_FIRST + i), (LPARAM) master_tty_interrupt); SendMessage (master_tty_window, SCREEN_SETBINDING, int_chars[i], (SCREEN_COMMAND_INTERRUPT_FIRST + i)); } return; } unsigned int DEFUN_VOID (OS_ctty_num_int_chars) { return (NUM_INT_CHANNELS); } cc_t * DEFUN_VOID (OS_ctty_get_int_chars) { return (&int_chars[0]); } void DEFUN (OS_ctty_set_int_chars, (new_int_chars), cc_t * new_int_chars) { int i; for (i = 0; i < NUM_INT_CHANNELS; i++) int_chars[i] = new_int_chars[i]; update_interrupt_characters (); return; } cc_t * DEFUN_VOID (OS_ctty_get_int_char_handlers) { return (&int_handlers[0]); } void DEFUN (OS_ctty_set_int_char_handlers, (new_int_handlers), cc_t * new_int_handlers) { int i; for (i = 0; i < NUM_INT_CHANNELS; i++) int_handlers[i] = new_int_handlers[i]; update_interrupt_characters (); return; } static void DEFUN (console_write_string, (string), unsigned char * string) { outf_console ("%s", string); outf_flush_console (); return; } static void DEFUN_VOID (initialize_keyboard_interrupt_table) { /* Set up default interrupt characters */ int_chars[0] = CONTROL_B; int_handlers[0] = ((unsigned char) interrupt_handler_control_b); int_chars[1] = CONTROL_G; int_handlers[1] = ((unsigned char) interrupt_handler_control_g); int_chars[2] = CONTROL_U; int_handlers[2] = ((unsigned char) interrupt_handler_control_u); int_chars[3] = CONTROL_X; int_handlers[3] = ((unsigned char) interrupt_handler_control_x); int_chars[4] = CONTROL_C; int_handlers[4] = ((unsigned char) interrupt_handler_interactive); int_chars[5] = CONTROL_BREAK; int_handlers[5] = ((unsigned char) interrupt_handler_terminate); keyboard_interrupt_enables = (CONTROL_B_ENABLE | CONTROL_G_ENABLE | CONTROL_U_ENABLE | CONTROL_X_ENABLE | INTERACTIVE_INTERRUPT_ENABLE | TERMINATE_INTERRUPT_ENABLE); update_interrupt_characters (); return; } static int hard_attn_limit = 2; static int hard_attn_counter = 0; cc_t DEFUN (OS_tty_map_interrupt_char, (int_char), cc_t int_char) { /* Scheme got a keyboard interrupt, reset the hard attention counter. */ hard_attn_counter = 0; return (int_char); } static void DEFUN_VOID (print_interrupt_help) { console_write_string ( "\r\nInterrupt choices are:\r\n" "C-G interrupt: ^G (abort to top level)\r\n" "C-X interrupt: ^x (abort)\r\n" "C-B interrupt: ^B (break)\r\n" "C-U interrupt: ^U (up)\r\n" "(exit) to exit Scheme\r\n" ); return; } extern void EXFUN (tty_set_next_interrupt_char, (cc_t)); #define REQUEST_INTERRUPT_IF_ENABLED(mask) do \ { \ if (keyboard_interrupt_enables & (mask)) \ { \ tty_set_next_interrupt_char ((cc_t) interrupt_char); \ interrupt_p = 1; \ } \ else \ interrupt_p = 0; \ } while (0) int DEFUN (signal_keyboard_character_interrupt, (c), int c) { if (c == -1) { if (keyboard_interrupt_enables & TERMINATE_INTERRUPT_ENABLE) goto interactive_interrupt; else return (0); } if (c == -2) { /* Special kludge for hard attn. */ if (keyboard_interrupt_enables & TERMINATE_INTERRUPT_ENABLE) { hard_attn_counter += 1; if (hard_attn_counter >= hard_attn_limit) { console_write_string ("\nTerminating scheme!"); termination_normal (0); } tty_set_next_interrupt_char (CONTROL_G_INTERRUPT_CHAR); } return (0); } else if ((c >= 0) && (c < KB_INT_TABLE_SIZE)) { int interrupt_p, interrupt_char; interrupt_char = keyboard_interrupt_table[c]; switch (interrupt_char) { case CONTROL_B_INTERRUPT_CHAR: REQUEST_INTERRUPT_IF_ENABLED (CONTROL_B_ENABLE); break; case CONTROL_G_INTERRUPT_CHAR: REQUEST_INTERRUPT_IF_ENABLED (CONTROL_G_ENABLE); break; case CONTROL_U_INTERRUPT_CHAR: REQUEST_INTERRUPT_IF_ENABLED (CONTROL_U_ENABLE); break; case CONTROL_X_INTERRUPT_CHAR: REQUEST_INTERRUPT_IF_ENABLED (CONTROL_X_ENABLE); break; case INTERACTIVE_INTERRUPT_CHAR: if (! (keyboard_interrupt_enables & INTERACTIVE_INTERRUPT_ENABLE)) { interrupt_p = 0; break; } interactive_interrupt: print_interrupt_help (); interrupt_p = 1; break; default: interrupt_p = 0; } return (interrupt_p); } return (0); } void DEFUN_VOID (OS_restartable_exit) { return; } /* System-level timer interrupt */ /* INT_Global_GC: High-priority Windows polling interrupt. INT_Global_1: Windows polling interrupt. */ #define CATATONIA_PERIOD 120000 /* msec */ #define ASYNC_TIMER_PERIOD 50 /* msec */ static void * timer_state = ((void *) NULL); extern unsigned long * win32_catatonia_block; static char * DEFUN_VOID (install_timer) { /* This presumes that the catatonia block is allocated near the register block and locked in physical memory with it. */ long catatonia_offset = (((SCHEME_OBJECT *) &win32_catatonia_block[0]) - (&Registers[0])); win32_catatonia_block[CATATONIA_BLOCK_COUNTER] = 0; win32_catatonia_block[CATATONIA_BLOCK_LIMIT] = (CATATONIA_PERIOD / ASYNC_TIMER_PERIOD); win32_catatonia_block[CATATONIA_BLOCK_FLAG] = 0; switch (win32_system_utilities.install_async_timer (&timer_state, &Registers[0], REGBLOCK_MEMTOP, REGBLOCK_INT_CODE, REGBLOCK_INT_MASK, (INT_Global_GC | INT_Global_1), catatonia_offset, WM_CATATONIC, WM_SCHEME_INTERRUPT, master_tty_window, OS_grab_interrupt_registers, OS_release_interrupt_registers)) { case WIN32_ASYNC_TIMER_OK: return (NULL); case WIN32_ASYNC_TIMER_NONE: return ("No asynchronous timer facilities available"); case WIN32_ASYNC_TIMER_EXHAUSTED: return ("No asynchronous timers available"); case WIN32_ASYNC_TIMER_RESOLUTION: return ("Wrong asynchronous timer resolution"); case WIN32_ASYNC_TIMER_NOLOCK: return ("Unable to lock the system timer interrupt handler"); case WIN32_ASYNC_TIMER_NOMEM: return ("Not enough memory to install the timer interrupt handler"); case WIN32_ASYNC_TIMER_NOLDT: return ("Not enough selectors to fix the timer interrupt handler"); default: return ("Unknown asynchronous timer return code"); } } static void DEFUN_VOID (flush_timer) { win32_system_utilities.flush_async_timer (timer_state); return; } /* This sets up the interrupt handlers for both DOS and NT, so that bands can be shared. */ void DEFUN (NT_initialize_fov, (fov), SCHEME_OBJECT fov) { int ctr, in; SCHEME_OBJECT iv, imv, prim; extern SCHEME_OBJECT EXFUN (make_primitive, (char *, int)); static int interrupt_numbers[2] = { Global_GC_Level, Global_1_Level, }; static long interrupt_masks[2] = { 0, /* No interrupts allowed */ (INT_Stack_Overflow | INT_Global_GC | INT_GC), }; iv = (FAST_VECTOR_REF (fov, System_Interrupt_Vector)); imv = (FAST_VECTOR_REF (fov, FIXOBJ_INTERRUPT_MASK_VECTOR)); prim = (make_primitive ("MICROCODE-POLL-INTERRUPT-HANDLER", 2)); for (ctr = 0; ctr < ((sizeof (interrupt_numbers)) / (sizeof (int))); ctr++) { in = interrupt_numbers[ctr]; VECTOR_SET (iv, in, prim); VECTOR_SET (imv, in, (long_to_integer (interrupt_masks[ctr]))); } return; } void DEFUN_VOID (NT_initialize_signals) { char * timer_error; initialize_keyboard_interrupt_table (); timer_error = (install_timer ()); if (timer_error) { outf_fatal ("install_timer: %s", timer_error); outf_flush_fatal (); abort (); } return; } extern void EXFUN (NT_restore_signals, (void)); void DEFUN_VOID (NT_restore_signals) { flush_timer (); return; }