b2g/simulator/packages/subprocess/lib/subprocess_worker_win.js

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
michael@0 4 */
michael@0 5
michael@0 6 /*
michael@0 7 * ChromeWorker Object subprocess.jsm on Windows to process stdin/stdout/stderr
michael@0 8 * on separate threads.
michael@0 9 *
michael@0 10 */
michael@0 11
michael@0 12 // Being a ChromeWorker object, implicitly uses the following:
michael@0 13 // Components.utils.import("resource://gre/modules/ctypes.jsm");
michael@0 14
michael@0 15 'use strict';
michael@0 16
michael@0 17 const BufferSize = 1024;
michael@0 18
michael@0 19 const BOOL = ctypes.bool;
michael@0 20 const HANDLE = ctypes.size_t;
michael@0 21 const DWORD = ctypes.uint32_t;
michael@0 22 const LPDWORD = DWORD.ptr;
michael@0 23 const PVOID = ctypes.voidptr_t;
michael@0 24 const LPVOID = PVOID;
michael@0 25
michael@0 26 /*
michael@0 27 typedef struct _OVERLAPPED {
michael@0 28 ULONG_PTR Internal;
michael@0 29 ULONG_PTR InternalHigh;
michael@0 30 union {
michael@0 31 struct {
michael@0 32 DWORD Offset;
michael@0 33 DWORD OffsetHigh;
michael@0 34 };
michael@0 35 PVOID Pointer;
michael@0 36 };
michael@0 37 HANDLE hEvent;
michael@0 38 } OVERLAPPED, *LPOVERLAPPED;
michael@0 39 */
michael@0 40 const OVERLAPPED = new ctypes.StructType("OVERLAPPED");
michael@0 41
michael@0 42 var ReadFileBuffer = ctypes.char.array(BufferSize);
michael@0 43 var WriteFileBuffer = ctypes.uint8_t.array(BufferSize);
michael@0 44
michael@0 45 var kernel32dll = null;
michael@0 46 var libFunc = {};
michael@0 47
michael@0 48 function initLib(libName) {
michael@0 49 if (ctypes.size_t.size == 8) {
michael@0 50 var WinABI = ctypes.default_abi;
michael@0 51 } else {
michael@0 52 var WinABI = ctypes.winapi_abi;
michael@0 53 }
michael@0 54
michael@0 55 kernel32dll = ctypes.open(libName);
michael@0 56
michael@0 57 /*
michael@0 58 BOOL WINAPI WriteFile(
michael@0 59 __in HANDLE hFile,
michael@0 60 __in LPCVOID lpBuffer,
michael@0 61 __in DWORD nNumberOfBytesToWrite,
michael@0 62 __out_opt LPDWORD lpNumberOfBytesWritten,
michael@0 63 __inout_opt LPOVERLAPPED lpOverlapped
michael@0 64 );
michael@0 65
michael@0 66 NOTE: lpBuffer is declared as array of unsigned int8 instead of char to avoid
michael@0 67 implicit charset conversion
michael@0 68 */
michael@0 69 libFunc.WriteFile = kernel32dll.declare("WriteFile",
michael@0 70 WinABI,
michael@0 71 BOOL,
michael@0 72 HANDLE,
michael@0 73 WriteFileBuffer,
michael@0 74 DWORD,
michael@0 75 LPDWORD,
michael@0 76 OVERLAPPED.ptr
michael@0 77 );
michael@0 78
michael@0 79 /*
michael@0 80 BOOL WINAPI ReadFile(
michael@0 81 __in HANDLE hFile,
michael@0 82 __out LPVOID ReadFileBuffer,
michael@0 83 __in DWORD nNumberOfBytesToRead,
michael@0 84 __out_opt LPDWORD lpNumberOfBytesRead,
michael@0 85 __inout_opt LPOVERLAPPED lpOverlapped
michael@0 86 );
michael@0 87 */
michael@0 88 libFunc.ReadFile = kernel32dll.declare("ReadFile",
michael@0 89 WinABI,
michael@0 90 BOOL,
michael@0 91 HANDLE,
michael@0 92 ReadFileBuffer,
michael@0 93 DWORD,
michael@0 94 LPDWORD,
michael@0 95 OVERLAPPED.ptr
michael@0 96 );
michael@0 97
michael@0 98 /*
michael@0 99 BOOL WINAPI CloseHandle(
michael@0 100 __in HANDLE hObject
michael@0 101 );
michael@0 102 */
michael@0 103 libFunc.CloseHandle = kernel32dll.declare("CloseHandle",
michael@0 104 WinABI,
michael@0 105 BOOL,
michael@0 106 HANDLE
michael@0 107 );
michael@0 108 }
michael@0 109
michael@0 110
michael@0 111 function writePipe(pipe, data) {
michael@0 112 var bytesWritten = DWORD(0);
michael@0 113
michael@0 114 var pData = new WriteFileBuffer();
michael@0 115
michael@0 116 var numChunks = Math.floor(data.length / BufferSize);
michael@0 117 for (var chunk = 0; chunk <= numChunks; chunk ++) {
michael@0 118 var numBytes = chunk < numChunks ? BufferSize : data.length - chunk * BufferSize;
michael@0 119 for (var i=0; i < numBytes; i++) {
michael@0 120 pData[i] = data.charCodeAt(chunk * BufferSize + i) % 256;
michael@0 121 }
michael@0 122
michael@0 123 var r = libFunc.WriteFile(pipe, pData, numBytes, bytesWritten.address(), null);
michael@0 124 if (bytesWritten.value != numBytes)
michael@0 125 throw("error: wrote "+bytesWritten.value+" instead of "+numBytes+" bytes");
michael@0 126 }
michael@0 127 postMessage("wrote "+data.length+" bytes of data");
michael@0 128 }
michael@0 129
michael@0 130 function readString(data, length, charset) {
michael@0 131 var string = '', bytes = [];
michael@0 132 for(var i = 0;i < length; i++) {
michael@0 133 if(data[i] == 0 && charset != "null") // stop on NULL character for non-binary data
michael@0 134 break;
michael@0 135
michael@0 136 bytes.push(data[i]);
michael@0 137 }
michael@0 138
michael@0 139 return bytes;
michael@0 140 }
michael@0 141
michael@0 142 function readPipe(pipe, charset) {
michael@0 143 while (true) {
michael@0 144 var bytesRead = DWORD(0);
michael@0 145 var line = new ReadFileBuffer();
michael@0 146 var r = libFunc.ReadFile(pipe, line, BufferSize, bytesRead.address(), null);
michael@0 147
michael@0 148 if (!r) {
michael@0 149 // stop if we get an error (such as EOF reached)
michael@0 150 postMessage({msg: "info", data: "ReadFile failed"});
michael@0 151 break;
michael@0 152 }
michael@0 153
michael@0 154 if (bytesRead.value > 0) {
michael@0 155 var c = readString(line, bytesRead.value, charset);
michael@0 156 postMessage({msg: "data", data: c, count: c.length});
michael@0 157 }
michael@0 158 else {
michael@0 159 break;
michael@0 160 }
michael@0 161 }
michael@0 162 libFunc.CloseHandle(pipe);
michael@0 163 postMessage({msg: "done"});
michael@0 164 kernel32dll.close();
michael@0 165 close();
michael@0 166 }
michael@0 167
michael@0 168 onmessage = function (event) {
michael@0 169 let pipePtr;
michael@0 170 switch (event.data.msg) {
michael@0 171 case "init":
michael@0 172 initLib(event.data.libc);
michael@0 173 break;
michael@0 174 case "write":
michael@0 175 // data contents:
michael@0 176 // msg: 'write'
michael@0 177 // data: the data (string) to write
michael@0 178 // pipe: ptr to pipe
michael@0 179 pipePtr = HANDLE.ptr(event.data.pipe);
michael@0 180 writePipe(pipePtr.contents, event.data.data);
michael@0 181 postMessage("WriteOK");
michael@0 182 break;
michael@0 183 case "read":
michael@0 184 initLib(event.data.libc);
michael@0 185 pipePtr = HANDLE.ptr(event.data.pipe);
michael@0 186 readPipe(pipePtr.contents, event.data.charset);
michael@0 187 break;
michael@0 188 case "close":
michael@0 189 pipePtr = HANDLE.ptr(event.data.pipe);
michael@0 190 postMessage("closing stdin\n");
michael@0 191
michael@0 192 if (libFunc.CloseHandle(pipePtr.contents)) {
michael@0 193 postMessage("ClosedOK");
michael@0 194 }
michael@0 195 else
michael@0 196 postMessage("Could not close stdin handle");
michael@0 197 break;
michael@0 198 case "stop":
michael@0 199 kernel32dll.close();
michael@0 200 close();
michael@0 201 break;
michael@0 202 default:
michael@0 203 throw("error: Unknown command"+event.data.msg+"\n");
michael@0 204 }
michael@0 205 return;
michael@0 206 };

mercurial