Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(21)

Side by Side Diff: bin/process_win.cc

Issue 8249007: Implement the full process interface for Windows (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/runtime/
Patch Set: '' Created 9 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « bin/process_impl.dart ('k') | bin/socket_win.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include <process.h>
6
5 #include "bin/builtin.h" 7 #include "bin/builtin.h"
6 #include "bin/globals.h" 8 #include "bin/globals.h"
7 #include "bin/process.h" 9 #include "bin/process.h"
10 #include "bin/eventhandler.h"
11
12 static const int kReadHandle = 0;
13 static const int kWriteHandle = 1;
14
15 class ProcessInfo {
16 public:
17 ProcessInfo(DWORD process_id, HANDLE process_handle, HANDLE exit_pipe)
18 : process_id_(process_id),
19 process_handle_(process_handle),
20 exit_pipe_(exit_pipe) { }
21
22 intptr_t pid() { return process_id_; }
23 HANDLE process_handle() { return process_handle_; }
24 HANDLE exit_pipe() { return exit_pipe_; }
25 ProcessInfo* next() { return next_; }
26 void set_next(ProcessInfo* next) { next_ = next; }
27
28 private:
29 DWORD process_id_; // Process id.
30 HANDLE process_handle_; // Process handle.
31 HANDLE exit_pipe_; // File descriptor for pipe to report exit code.
32 ProcessInfo* next_;
33 };
34
35
36 ProcessInfo* active_processes = NULL;
37
38
39 static void AddProcess(ProcessInfo* process) {
40 process->set_next(active_processes);
41 active_processes = process;
42 }
43
44
45 static ProcessInfo* LookupProcess(intptr_t pid) {
46 ProcessInfo* current = active_processes;
47 while (current != NULL) {
48 if (current->pid() == pid) {
49 return current;
50 }
51 current = current->next();
52 }
53 return NULL;
54 }
55
56
57 static void RemoveProcess(intptr_t pid) {
58 ProcessInfo* prev = NULL;
59 ProcessInfo* current = active_processes;
60 while (current != NULL) {
61 if (current->pid() == pid) {
62 if (prev == NULL) {
63 active_processes = current->next();
64 } else {
65 prev->set_next(current->next());
66 }
67 delete current;
68 return;
69 }
70 prev = current;
71 current = current->next();
72 }
73 }
74
75
76 // Create a pipe for communicating with a new process. The handles array
77 // will contain the read and write ends of the pipe. Based on the is_input
78 // argument either the read or the write end of the handle will be
79 // non-inherited.
80 static bool CreateProcessPipe(HANDLE handles[2],
81 char* pipe_name,
82 bool is_input) {
83 SECURITY_ATTRIBUTES security_attributes;
84 security_attributes.nLength = sizeof(SECURITY_ATTRIBUTES);
85 security_attributes.bInheritHandle = TRUE;
86 security_attributes.lpSecurityDescriptor = NULL;
87 if (is_input) {
88 handles[kWriteHandle] =
89 CreateNamedPipe(pipe_name,
90 PIPE_ACCESS_OUTBOUND | FILE_FLAG_OVERLAPPED,
91 PIPE_TYPE_BYTE | PIPE_WAIT,
92 1, // Number of pipes
93 1024, // Out buffer size
94 1024, // In buffer size
95 0, // Timeout in ms
96 NULL);
97
98 if (handles[kWriteHandle] == INVALID_HANDLE_VALUE) {
99 fprintf(stderr, "CreateNamedPipe failed %d\n", GetLastError());
100 return false;
101 }
102
103 handles[kReadHandle] =
104 CreateFile(pipe_name,
105 GENERIC_READ,
106 0,
107 &security_attributes,
108 OPEN_EXISTING,
109 FILE_READ_ATTRIBUTES | FILE_FLAG_OVERLAPPED,
110 NULL);
111 if (handles[kReadHandle] == INVALID_HANDLE_VALUE) {
112 fprintf(stderr, "CreateFile failed %d\n", GetLastError());
113 return false;
114 }
115 } else {
116 handles[kReadHandle] =
117 CreateNamedPipe(pipe_name,
118 PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
119 PIPE_TYPE_BYTE | PIPE_WAIT,
120 1, // Number of pipes
121 1024, // Out buffer size
122 1024, // In buffer size
123 0, // Timeout in ms
124 NULL);
125
126 if (handles[kReadHandle] == INVALID_HANDLE_VALUE) {
127 fprintf(stderr, "CreateNamedPipe failed %d\n", GetLastError());
128 return false;
129 }
130
131 handles[kWriteHandle] =
132 CreateFile(pipe_name,
133 GENERIC_WRITE,
134 0,
135 &security_attributes,
136 OPEN_EXISTING,
137 FILE_WRITE_ATTRIBUTES | FILE_FLAG_OVERLAPPED,
138 NULL);
139 if (handles[kWriteHandle] == INVALID_HANDLE_VALUE) {
140 fprintf(stderr, "CreateFile failed %d\n", GetLastError());
141 return false;
142 }
143 }
144 return true;
145 }
146
147
148 static void CloseProcessPipe(HANDLE handles[2]) {
149 for (int i = kReadHandle; i < kWriteHandle; i++) {
150 if (handles[i] != INVALID_HANDLE_VALUE) {
151 if (!CloseHandle(handles[i])) {
152 fprintf(stderr, "CloseHandle failed %d\n", GetLastError());
153 }
154 handles[i] = INVALID_HANDLE_VALUE;
155 }
156 }
157 }
158
159
160 static int SetOsErrorMessage(char* os_error_message,
161 int os_error_message_len) {
162 int error_code = GetLastError();
163 // TODO(sgjesse): Use FormatMessage to get the error message.
164 char message[80];
165 snprintf(os_error_message, os_error_message_len, "OS Error %d", error_code);
166 return error_code;
167 }
168
169
170 static unsigned int __stdcall TerminationWaitThread(void* args) {
171 ProcessInfo* process = reinterpret_cast<ProcessInfo*>(args);
172 WaitForSingleObject(process->process_handle(), INFINITE);
173 DWORD exit_code;
174 BOOL ok = GetExitCodeProcess(process->process_handle(), &exit_code);
175 if (!ok) {
176 fprintf(stderr, "GetExitCodeProcess failed %d\n", GetLastError());
177 }
178 intptr_t message[2] = { process->pid(), static_cast<intptr_t>(exit_code) };
179 DWORD written;
180 ok = WriteFile(
181 process->exit_pipe(), message, sizeof(message), &written, NULL);
182 if (!ok || written != 8) {
183 fprintf(stderr, "FileWrite failed %d\n", GetLastError());
184 }
185 return 0;
186 }
187
8 188
9 int Process::Start(const char* path, 189 int Process::Start(const char* path,
10 char* arguments[], 190 char* arguments[],
11 intptr_t arguments_length, 191 intptr_t arguments_length,
12 intptr_t* in, 192 intptr_t* in,
13 intptr_t* out, 193 intptr_t* out,
14 intptr_t* err, 194 intptr_t* err,
15 intptr_t* id, 195 intptr_t* id,
16 intptr_t* exit_event, 196 intptr_t* exit_handler,
17 char* os_error_message, 197 char* os_error_message,
18 int os_error_message_len) { 198 int os_error_message_len) {
199 HANDLE stdin_handles[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE };
200 HANDLE stdout_handles[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE };
201 HANDLE stderr_handles[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE };
202 HANDLE exit_handles[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE };
203 // TODO(sgjesse): Find a better way of generating unique pipe names
204 // (e.g. UUID).
205 DWORD current_pid = GetCurrentProcessId();
206 static int pipe_id = 0;
207 char pipe_name[80];
208 pipe_id++;
209 snprintf(pipe_name, sizeof(pipe_name),
210 "\\\\.\\Pipe\\dart%d_%d_1", current_pid, pipe_id);
211 if (!CreateProcessPipe(stdin_handles, pipe_name, true)) {
212 int error_code = SetOsErrorMessage(os_error_message, os_error_message_len);
213 CloseProcessPipe(stdin_handles);
214 return error_code;
215 }
216 snprintf(pipe_name, sizeof(pipe_name),
217 "\\\\.\\Pipe\\dart%d_%d_2", current_pid, pipe_id);
218 if (!CreateProcessPipe(stdout_handles, pipe_name, false)) {
219 int error_code = SetOsErrorMessage(os_error_message, os_error_message_len);
220 CloseProcessPipe(stdin_handles);
221 CloseProcessPipe(stdout_handles);
222 return error_code;
223 }
224 snprintf(pipe_name, sizeof(pipe_name),
225 "\\\\.\\Pipe\\dart%d_%d_3", current_pid, pipe_id);
226 if (!CreateProcessPipe(stderr_handles, pipe_name, false)) {
227 int error_code = SetOsErrorMessage(os_error_message, os_error_message_len);
228 CloseProcessPipe(stdin_handles);
229 CloseProcessPipe(stdout_handles);
230 CloseProcessPipe(stderr_handles);
231 return error_code;
232 }
233 snprintf(pipe_name, sizeof(pipe_name),
234 "\\\\.\\Pipe\\dart%d_%d_4", current_pid, pipe_id);
235 if (!CreateProcessPipe(exit_handles, pipe_name, false)) {
236 int error_code = SetOsErrorMessage(os_error_message, os_error_message_len);
237 CloseProcessPipe(stdin_handles);
238 CloseProcessPipe(stdout_handles);
239 CloseProcessPipe(stderr_handles);
240 CloseProcessPipe(exit_handles);
241 return error_code;
242 }
243
19 // Setup info structures. 244 // Setup info structures.
20 STARTUPINFO startup_info; 245 STARTUPINFO startup_info;
21 PROCESS_INFORMATION process_info;
22 ZeroMemory(&startup_info, sizeof(startup_info)); 246 ZeroMemory(&startup_info, sizeof(startup_info));
23 startup_info.cb = sizeof(startup_info); 247 startup_info.cb = sizeof(startup_info);
248 startup_info.hStdInput = stdin_handles[kReadHandle];
249 startup_info.hStdOutput = stdout_handles[kWriteHandle];
250 startup_info.hStdError = stderr_handles[kWriteHandle];
251 startup_info.dwFlags |= STARTF_USESTDHANDLES;
252
253 PROCESS_INFORMATION process_info;
24 ZeroMemory(&process_info, sizeof(process_info)); 254 ZeroMemory(&process_info, sizeof(process_info));
25 255
26 // TODO(ager): Once sockets are implemented, use the supplied
27 // arguments as in, out and err in the startup info.
28
29 // Compute command-line length. 256 // Compute command-line length.
30 int command_line_length = strlen(path); 257 int command_line_length = strlen(path);
31 for (int i = 0; i < arguments_length; i++) { 258 for (int i = 0; i < arguments_length; i++) {
32 command_line_length += strlen(arguments[i]); 259 command_line_length += strlen(arguments[i]);
33 } 260 }
34 // Account for two occurrences of '"' around the command, one 261 // Account for two occurrences of '"' around the command, one
35 // space per argument and a terminating '\0'. 262 // space per argument and a terminating '\0'.
36 command_line_length += 2 + arguments_length + 1; 263 command_line_length += 2 + arguments_length + 1;
37 static const int kMaxCommandLineLength = 32768; 264 static const int kMaxCommandLineLength = 32768;
38 if (command_line_length > kMaxCommandLineLength) { 265 if (command_line_length > kMaxCommandLineLength) {
39 return 1; 266 int error_code = SetOsErrorMessage(os_error_message, os_error_message_len);
267 CloseProcessPipe(stdin_handles);
268 CloseProcessPipe(stdout_handles);
269 CloseProcessPipe(stderr_handles);
270 CloseProcessPipe(exit_handles);
271 return error_code;
40 } 272 }
41 273
42 // Put together command-line string. 274 // Put together command-line string.
43 char* command_line = new char[command_line_length]; 275 char* command_line = new char[command_line_length];
44 int len = 0; 276 int len = 0;
45 int remaining = command_line_length; 277 int remaining = command_line_length;
46 int written = snprintf(command_line + len, remaining, "\"%s\"", path); 278 int written = snprintf(command_line + len, remaining, "\"%s\"", path);
47 len += written; 279 len += written;
48 remaining -= written; 280 remaining -= written;
49 ASSERT(remaining >= 0); 281 ASSERT(remaining >= 0);
50 for (int i = 0; i < arguments_length; i++) { 282 for (int i = 0; i < arguments_length; i++) {
51 written = snprintf(command_line + len, remaining, " %s", arguments[i]); 283 written = snprintf(command_line + len, remaining, " %s", arguments[i]);
52 len += written; 284 len += written;
53 remaining -= written; 285 remaining -= written;
54 ASSERT(remaining >= 0); 286 ASSERT(remaining >= 0);
55 } 287 }
56 288
57 // Create process. 289 // Create process.
58 BOOL result = CreateProcess(NULL, // ApplicationName 290 BOOL result = CreateProcess(NULL, // ApplicationName
59 command_line, 291 command_line,
60 NULL, // ProcessAttributes 292 NULL, // ProcessAttributes
61 NULL, // ThreadAttributes 293 NULL, // ThreadAttributes
62 FALSE, // InheritHandles 294 TRUE, // InheritHandles
63 0, // CreationFlags 295 0, // CreationFlags
64 NULL, // Environment 296 NULL, // Environment
65 NULL, // CurrentDirectory, 297 NULL, // CurrentDirectory,
66 &startup_info, 298 &startup_info,
67 &process_info); 299 &process_info);
68 300
69 // Deallocate command-line string. 301 // Deallocate command-line string.
70 delete[] command_line; 302 delete[] command_line;
71 303
72 if (result == 0) { 304 if (result == 0) {
73 return 1; 305 int error_code = SetOsErrorMessage(os_error_message, os_error_message_len);
306 CloseProcessPipe(stdin_handles);
307 CloseProcessPipe(stdout_handles);
308 CloseProcessPipe(stderr_handles);
309 CloseProcessPipe(exit_handles);
310 return error_code;
74 } 311 }
75 312
76 // Return process handle. 313 ProcessInfo* process = new ProcessInfo(process_info.dwProcessId,
77 *id = reinterpret_cast<intptr_t>(process_info.hProcess); 314 process_info.hProcess,
315 exit_handles[kWriteHandle]);
316 AddProcess(process);
317
318 // TODO(sgjesse): Don't use a separate thread for waiting for each process to
319 // terminate.
320 uint32_t tid;
321 uintptr_t thread_handle =
322 _beginthreadex(NULL, 32 * 1024, TerminationWaitThread, process, 0, &tid);
323 if (thread_handle == -1) {
324 FATAL("Failed to start event handler thread");
325 }
326
327
328 // Connect the three std streams.
329 FileHandle* stdin_handle = new FileHandle(stdin_handles[kWriteHandle]);
330 CloseHandle(stdin_handles[kReadHandle]);
331 FileHandle* stdout_handle = new FileHandle(stdout_handles[kReadHandle]);
332 CloseHandle(stdout_handles[kWriteHandle]);
333 FileHandle* stderr_handle = new FileHandle(stderr_handles[kReadHandle]);
334 CloseHandle(stderr_handles[kWriteHandle]);
335 FileHandle* exit_handle = new FileHandle(exit_handles[kReadHandle]);
336 *in = reinterpret_cast<intptr_t>(stdout_handle);
337 *out = reinterpret_cast<intptr_t>(stdin_handle);
338 *err = reinterpret_cast<intptr_t>(stderr_handle);
339 *exit_handler = reinterpret_cast<intptr_t>(exit_handle);
340
341 CloseHandle(process_info.hThread);
342
343 // Return process id.
344 *id = process->pid();
78 return 0; 345 return 0;
79 } 346 }
80 347
81 348
82 bool Process::Kill(intptr_t id) { 349 bool Process::Kill(intptr_t id) {
83 HANDLE process_handle = reinterpret_cast<HANDLE>(id); 350 ProcessInfo* process = LookupProcess(id);
84 BOOL result = TerminateProcess(process_handle, -1); 351 ASSERT(process != NULL);
85 if (result == 0) { 352 if (process != NULL) {
86 return false; 353 BOOL result = TerminateProcess(process->process_handle(), -1);
354 if (result == 0) {
355 return false;
356 }
87 } 357 }
88 CloseHandle(process_handle);
89 return true; 358 return true;
90 } 359 }
91 360
92 361
93 void Process::Exit(intptr_t id) { 362 void Process::Exit(intptr_t id) {
363 RemoveProcess(id);
94 } 364 }
OLDNEW
« no previous file with comments | « bin/process_impl.dart ('k') | bin/socket_win.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698