Windows: ensure 'kill subprocesses end with Racket
Use a job object to ensure that subprocesses that are meant to be killed by the current custodian are reliably terminated if Racket exits for any reason.
This commit is contained in:
parent
afa01fa763
commit
cefcbdf802
|
@ -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_)
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user