diff --git a/racket/src/racket/include/schthread.h b/racket/src/racket/include/schthread.h index 817f6a3c3e..2bf55034d5 100644 --- a/racket/src/racket/include/schthread.h +++ b/racket/src/racket/include/schthread.h @@ -202,6 +202,7 @@ typedef struct Thread_Local_Variables { struct Scheme_Custodian *new_port_cust_; #if (defined(__WIN32__) || defined(WIN32) || defined(_WIN32)) void *scheme_break_semaphore_; + void *process_job_object_; #else int external_event_fd_; int put_external_event_fd_; @@ -598,6 +599,7 @@ XFORM_GC_VARIABLE_STACK_THROUGH_THREAD_LOCAL; #define locked_fd_process_map XOA (scheme_get_thread_local_variables()->locked_fd_process_map_) #define new_port_cust XOA (scheme_get_thread_local_variables()->new_port_cust_) #define scheme_break_semaphore XOA (scheme_get_thread_local_variables()->scheme_break_semaphore_) +#define process_job_object XOA (scheme_get_thread_local_variables()->process_job_object_) #define external_event_fd XOA (scheme_get_thread_local_variables()->external_event_fd_) #define put_external_event_fd XOA (scheme_get_thread_local_variables()->put_external_event_fd_) #define read_string_byte_buffer XOA (scheme_get_thread_local_variables()->read_string_byte_buffer_) diff --git a/racket/src/racket/src/env.c b/racket/src/racket/src/env.c index 6c4a9730b8..6b91ab4701 100644 --- a/racket/src/racket/src/env.c +++ b/racket/src/racket/src/env.c @@ -656,6 +656,10 @@ void scheme_place_instance_destroy(int force) else scheme_run_atexit_closers_on_all(force_more_closed_after); +#ifdef WINDOWS_PROCESSES + scheme_release_process_job_object(); +#endif + scheme_release_file_descriptor(); scheme_end_futures_per_place(); diff --git a/racket/src/racket/src/port.c b/racket/src/racket/src/port.c index 44d3c0e930..c5202e4205 100644 --- a/racket/src/racket/src/port.c +++ b/racket/src/racket/src/port.c @@ -9417,6 +9417,17 @@ static Scheme_Object *do_subprocess_kill(Scheme_Object *_sp, Scheme_Object *kill return NULL; } +#ifdef WINDOWS_PROCESSES +void scheme_release_process_job_object(void) +{ + if (process_job_object) { + TerminateJobObject((HANDLE)process_job_object, 1); + CloseHandle((HANDLE)process_job_object); + process_job_object = NULL; + } +} +#endif + static void kill_subproc(Scheme_Object *o, void *data) { (void)do_subprocess_kill(o, scheme_true, 0); @@ -9569,10 +9580,10 @@ static char *cmdline_protect(char *s) static intptr_t mz_spawnv(char *command, const char * const *argv, int exact_cmdline, intptr_t sin, intptr_t sout, intptr_t serr, int *pid, - int new_process_group, + int new_process_group, Scheme_Object *cust_mode, void *env, char *wd) { - int i, l, len = 0; + int i, l, len = 0, use_jo; intptr_t cr_flag; char *cmdline; STARTUPINFOW startup; @@ -9617,10 +9628,30 @@ static intptr_t mz_spawnv(char *command, const char * const *argv, cr_flag |= CREATE_NEW_PROCESS_GROUP; cr_flag |= CREATE_UNICODE_ENVIRONMENT; + use_jo = SCHEME_SYMBOLP(cust_mode) && !strcmp(SCHEME_SYM_VAL(cust_mode), "kill"); + if (use_jo) { + /* Use a job object to ensure that the new process will be terminated + if this process ends for any reason (including a crash) */ + if (!process_job_object) { + GC_CAN_IGNORE JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli; + + process_job_object = (void*)CreateJobObject(NULL, NULL); + + memset(&jeli, 0, sizeof(jeli)); + jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; + SetInformationJobObject((HANDLE)process_job_object, + JobObjectExtendedLimitInformation, + &jeli, + sizeof(jeli)); + } + } + if (CreateProcessW(WIDE_PATH_COPY(command), WIDE_PATH_COPY(cmdline), NULL, NULL, 1 /*inherit*/, cr_flag, env, WIDE_PATH_COPY(wd), &startup, &info)) { + if (use_jo) + AssignProcessToJobObject((HANDLE)process_job_object, info.hProcess); CloseHandle(info.hThread); *pid = info.dwProcessId; return (intptr_t)info.hProcess; @@ -9952,7 +9983,7 @@ static Scheme_Object *subprocess(int c, Scheme_Object *args[]) from_subprocess[1], err_subprocess[1], &pid, - new_process_group, + new_process_group, cust_mode, env, SCHEME_BYTE_STR_VAL(tcd)); if (spawn_status != -1) diff --git a/racket/src/racket/src/schpriv.h b/racket/src/racket/src/schpriv.h index a4ed95e79e..b536986f5d 100644 --- a/racket/src/racket/src/schpriv.h +++ b/racket/src/racket/src/schpriv.h @@ -417,6 +417,7 @@ void scheme_init_exn_config(void); #endif #ifdef WINDOWS_PROCESSES void scheme_init_thread_memory(void); +void scheme_release_process_job_object(void); #endif void scheme_init_module_resolver(void);