1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/b2g/simulator/packages/subprocess/lib/subprocess_worker_win.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,206 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. 1.7 + */ 1.8 + 1.9 +/* 1.10 + * ChromeWorker Object subprocess.jsm on Windows to process stdin/stdout/stderr 1.11 + * on separate threads. 1.12 + * 1.13 + */ 1.14 + 1.15 +// Being a ChromeWorker object, implicitly uses the following: 1.16 +// Components.utils.import("resource://gre/modules/ctypes.jsm"); 1.17 + 1.18 +'use strict'; 1.19 + 1.20 +const BufferSize = 1024; 1.21 + 1.22 +const BOOL = ctypes.bool; 1.23 +const HANDLE = ctypes.size_t; 1.24 +const DWORD = ctypes.uint32_t; 1.25 +const LPDWORD = DWORD.ptr; 1.26 +const PVOID = ctypes.voidptr_t; 1.27 +const LPVOID = PVOID; 1.28 + 1.29 +/* 1.30 +typedef struct _OVERLAPPED { 1.31 + ULONG_PTR Internal; 1.32 + ULONG_PTR InternalHigh; 1.33 + union { 1.34 + struct { 1.35 + DWORD Offset; 1.36 + DWORD OffsetHigh; 1.37 + }; 1.38 + PVOID Pointer; 1.39 + }; 1.40 + HANDLE hEvent; 1.41 +} OVERLAPPED, *LPOVERLAPPED; 1.42 +*/ 1.43 +const OVERLAPPED = new ctypes.StructType("OVERLAPPED"); 1.44 + 1.45 +var ReadFileBuffer = ctypes.char.array(BufferSize); 1.46 +var WriteFileBuffer = ctypes.uint8_t.array(BufferSize); 1.47 + 1.48 +var kernel32dll = null; 1.49 +var libFunc = {}; 1.50 + 1.51 +function initLib(libName) { 1.52 + if (ctypes.size_t.size == 8) { 1.53 + var WinABI = ctypes.default_abi; 1.54 + } else { 1.55 + var WinABI = ctypes.winapi_abi; 1.56 + } 1.57 + 1.58 + kernel32dll = ctypes.open(libName); 1.59 + 1.60 + /* 1.61 + BOOL WINAPI WriteFile( 1.62 + __in HANDLE hFile, 1.63 + __in LPCVOID lpBuffer, 1.64 + __in DWORD nNumberOfBytesToWrite, 1.65 + __out_opt LPDWORD lpNumberOfBytesWritten, 1.66 + __inout_opt LPOVERLAPPED lpOverlapped 1.67 + ); 1.68 + 1.69 + NOTE: lpBuffer is declared as array of unsigned int8 instead of char to avoid 1.70 + implicit charset conversion 1.71 + */ 1.72 + libFunc.WriteFile = kernel32dll.declare("WriteFile", 1.73 + WinABI, 1.74 + BOOL, 1.75 + HANDLE, 1.76 + WriteFileBuffer, 1.77 + DWORD, 1.78 + LPDWORD, 1.79 + OVERLAPPED.ptr 1.80 + ); 1.81 + 1.82 + /* 1.83 + BOOL WINAPI ReadFile( 1.84 + __in HANDLE hFile, 1.85 + __out LPVOID ReadFileBuffer, 1.86 + __in DWORD nNumberOfBytesToRead, 1.87 + __out_opt LPDWORD lpNumberOfBytesRead, 1.88 + __inout_opt LPOVERLAPPED lpOverlapped 1.89 + ); 1.90 + */ 1.91 + libFunc.ReadFile = kernel32dll.declare("ReadFile", 1.92 + WinABI, 1.93 + BOOL, 1.94 + HANDLE, 1.95 + ReadFileBuffer, 1.96 + DWORD, 1.97 + LPDWORD, 1.98 + OVERLAPPED.ptr 1.99 + ); 1.100 + 1.101 + /* 1.102 + BOOL WINAPI CloseHandle( 1.103 + __in HANDLE hObject 1.104 + ); 1.105 + */ 1.106 + libFunc.CloseHandle = kernel32dll.declare("CloseHandle", 1.107 + WinABI, 1.108 + BOOL, 1.109 + HANDLE 1.110 + ); 1.111 +} 1.112 + 1.113 + 1.114 +function writePipe(pipe, data) { 1.115 + var bytesWritten = DWORD(0); 1.116 + 1.117 + var pData = new WriteFileBuffer(); 1.118 + 1.119 + var numChunks = Math.floor(data.length / BufferSize); 1.120 + for (var chunk = 0; chunk <= numChunks; chunk ++) { 1.121 + var numBytes = chunk < numChunks ? BufferSize : data.length - chunk * BufferSize; 1.122 + for (var i=0; i < numBytes; i++) { 1.123 + pData[i] = data.charCodeAt(chunk * BufferSize + i) % 256; 1.124 + } 1.125 + 1.126 + var r = libFunc.WriteFile(pipe, pData, numBytes, bytesWritten.address(), null); 1.127 + if (bytesWritten.value != numBytes) 1.128 + throw("error: wrote "+bytesWritten.value+" instead of "+numBytes+" bytes"); 1.129 + } 1.130 + postMessage("wrote "+data.length+" bytes of data"); 1.131 +} 1.132 + 1.133 +function readString(data, length, charset) { 1.134 + var string = '', bytes = []; 1.135 + for(var i = 0;i < length; i++) { 1.136 + if(data[i] == 0 && charset != "null") // stop on NULL character for non-binary data 1.137 + break; 1.138 + 1.139 + bytes.push(data[i]); 1.140 + } 1.141 + 1.142 + return bytes; 1.143 +} 1.144 + 1.145 +function readPipe(pipe, charset) { 1.146 + while (true) { 1.147 + var bytesRead = DWORD(0); 1.148 + var line = new ReadFileBuffer(); 1.149 + var r = libFunc.ReadFile(pipe, line, BufferSize, bytesRead.address(), null); 1.150 + 1.151 + if (!r) { 1.152 + // stop if we get an error (such as EOF reached) 1.153 + postMessage({msg: "info", data: "ReadFile failed"}); 1.154 + break; 1.155 + } 1.156 + 1.157 + if (bytesRead.value > 0) { 1.158 + var c = readString(line, bytesRead.value, charset); 1.159 + postMessage({msg: "data", data: c, count: c.length}); 1.160 + } 1.161 + else { 1.162 + break; 1.163 + } 1.164 + } 1.165 + libFunc.CloseHandle(pipe); 1.166 + postMessage({msg: "done"}); 1.167 + kernel32dll.close(); 1.168 + close(); 1.169 +} 1.170 + 1.171 +onmessage = function (event) { 1.172 + let pipePtr; 1.173 + switch (event.data.msg) { 1.174 + case "init": 1.175 + initLib(event.data.libc); 1.176 + break; 1.177 + case "write": 1.178 + // data contents: 1.179 + // msg: 'write' 1.180 + // data: the data (string) to write 1.181 + // pipe: ptr to pipe 1.182 + pipePtr = HANDLE.ptr(event.data.pipe); 1.183 + writePipe(pipePtr.contents, event.data.data); 1.184 + postMessage("WriteOK"); 1.185 + break; 1.186 + case "read": 1.187 + initLib(event.data.libc); 1.188 + pipePtr = HANDLE.ptr(event.data.pipe); 1.189 + readPipe(pipePtr.contents, event.data.charset); 1.190 + break; 1.191 + case "close": 1.192 + pipePtr = HANDLE.ptr(event.data.pipe); 1.193 + postMessage("closing stdin\n"); 1.194 + 1.195 + if (libFunc.CloseHandle(pipePtr.contents)) { 1.196 + postMessage("ClosedOK"); 1.197 + } 1.198 + else 1.199 + postMessage("Could not close stdin handle"); 1.200 + break; 1.201 + case "stop": 1.202 + kernel32dll.close(); 1.203 + close(); 1.204 + break; 1.205 + default: 1.206 + throw("error: Unknown command"+event.data.msg+"\n"); 1.207 + } 1.208 + return; 1.209 +};