-
Notifications
You must be signed in to change notification settings - Fork 183
Expand file tree
/
Copy pathlwt_process_stubs.c
More file actions
175 lines (142 loc) · 4.58 KB
/
lwt_process_stubs.c
File metadata and controls
175 lines (142 loc) · 4.58 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
/* This file is part of Lwt, released under the MIT license. See LICENSE.md for
details, or visit https://github.com/ocsigen/lwt/blob/master/LICENSE.md. */
#include "lwt_config.h"
#if defined(LWT_ON_WINDOWS)
#include <lwt_unix.h>
#if OCAML_VERSION < 41300
#define CAML_INTERNALS
#endif
#include <caml/alloc.h>
#include <caml/fail.h>
#include <caml/memory.h>
#include <caml/osdeps.h>
static HANDLE get_handle(value opt) {
value fd;
if (Is_some(opt)) {
fd = Some_val(opt);
if (Descr_kind_val(fd) == KIND_SOCKET) {
win32_maperr(ERROR_INVALID_HANDLE);
uerror("CreateProcess", Nothing);
return NULL;
} else
return Handle_val(fd);
} else
return INVALID_HANDLE_VALUE;
}
/* Ensures the handle [h] is inheritable. Returns the handle for the
child process in [hStd] and in [to_close] if it needs to be closed
after CreateProcess. */
static int ensure_inheritable(HANDLE h /* in */,
HANDLE * hStd /* out */,
HANDLE * to_close /* out */)
{
DWORD flags;
HANDLE hp;
if (h == INVALID_HANDLE_VALUE || h == NULL)
return 1;
if (! GetHandleInformation(h, &flags))
return 0;
hp = GetCurrentProcess();
if (! (flags & HANDLE_FLAG_INHERIT)) {
if (! DuplicateHandle(hp, h, hp, hStd, 0, TRUE, DUPLICATE_SAME_ACCESS))
return 0;
*to_close = *hStd;
} else {
*hStd = h;
}
return 1;
}
CAMLprim value lwt_process_create_process(value prog, value cmdline, value env,
value cwd, value fds) {
CAMLparam5(prog, cmdline, env, cwd, fds);
CAMLlocal1(result);
STARTUPINFO si;
PROCESS_INFORMATION pi;
DWORD flags = 0, err;
HANDLE hp, fd0, fd1, fd2;
HANDLE to_close0 = INVALID_HANDLE_VALUE, to_close1 = INVALID_HANDLE_VALUE,
to_close2 = INVALID_HANDLE_VALUE;
fd0 = get_handle(Field(fds, 0));
fd1 = get_handle(Field(fds, 1));
fd2 = get_handle(Field(fds, 2));
err = ERROR_SUCCESS;
ZeroMemory(&si, sizeof(si));
ZeroMemory(&pi, sizeof(pi));
si.cb = sizeof(si);
si.dwFlags = STARTF_USESTDHANDLES;
/* If needed, duplicate the handles fd1, fd2, fd3 to make sure they
are inheritable. */
if (! ensure_inheritable(fd0, &si.hStdInput, &to_close0) ||
! ensure_inheritable(fd1, &si.hStdOutput, &to_close1) ||
! ensure_inheritable(fd2, &si.hStdError, &to_close2)) {
err = GetLastError(); goto ret;
}
#define string_option(opt) \
(Is_block(opt) ? caml_stat_strdup_to_os(String_val(Field(opt, 0))) : NULL)
char_os
*progs = string_option(prog),
*cmdlines = caml_stat_strdup_to_os(String_val(cmdline)),
*envs = string_option(env),
*cwds = string_option(cwd);
#undef string_option
flags |= CREATE_UNICODE_ENVIRONMENT;
if (! CreateProcess(progs, cmdlines, NULL, NULL, TRUE, flags,
envs, cwds, &si, &pi)) {
err = GetLastError();
}
caml_stat_free(progs);
caml_stat_free(cmdlines);
caml_stat_free(envs);
caml_stat_free(cwds);
ret:
/* Close the handles if we duplicated them above. */
if (to_close0 != INVALID_HANDLE_VALUE) CloseHandle(to_close0);
if (to_close1 != INVALID_HANDLE_VALUE) CloseHandle(to_close1);
if (to_close2 != INVALID_HANDLE_VALUE) CloseHandle(to_close2);
if (err != ERROR_SUCCESS) {
win32_maperr(err);
uerror("CreateProcess", Nothing);
}
CloseHandle(pi.hThread);
result = caml_alloc_tuple(2);
Store_field(result, 0, Val_int(pi.dwProcessId));
Store_field(result, 1, win_alloc_handle(pi.hProcess));
CAMLreturn(result);
}
struct job_wait {
struct lwt_unix_job job;
HANDLE handle;
};
static void worker_wait(struct job_wait *job) {
WaitForSingleObject(job->handle, INFINITE);
}
static value result_wait(struct job_wait *job) {
DWORD code, error;
if (!GetExitCodeProcess(job->handle, &code)) {
error = GetLastError();
CloseHandle(job->handle);
lwt_unix_free_job(&job->job);
win32_maperr(error);
uerror("GetExitCodeProcess", Nothing);
}
CloseHandle(job->handle);
lwt_unix_free_job(&job->job);
return Val_int(code);
}
CAMLprim value lwt_process_wait_job(value handle) {
LWT_UNIX_INIT_JOB(job, wait, 0);
job->handle = Handle_val(handle);
return lwt_unix_alloc_job(&(job->job));
}
CAMLprim value lwt_process_terminate_process(value handle, value code) {
if (!TerminateProcess(Handle_val(handle), Int_val(code))) {
win32_maperr(GetLastError());
uerror("TerminateProcess", Nothing);
}
return Val_unit;
}
#else /* defined(LWT_ON_WINDOWS) */
/* This is used to suppress a warning from ranlib about the object file having
no symbols. */
void lwt_process_dummy_symbol() {}
#endif /* defined(LWT_ON_WINDOWS) */