forked from mirrors/gecko-dev
		
	 b503616295
			
		
	
	
		b503616295
		
	
	
	
	
		
			
			# ignore-this-changeset Differential Revision: https://phabricator.services.mozilla.com/D36056 --HG-- extra : source : 2616392f26053ee376b9126fbca696de5d4bb15b
		
			
				
	
	
		
			527 lines
		
	
	
	
		
			13 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			527 lines
		
	
	
	
		
			13 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
 | |
| /* vim: set sts=2 sw=2 et tw=80: */
 | |
| /* This Source Code Form is subject to the terms of the Mozilla Public
 | |
|  * License, v. 2.0. If a copy of the MPL was not distributed with this
 | |
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | |
| "use strict";
 | |
| 
 | |
| /* exported LIBC, Win, createPipe, libc */
 | |
| 
 | |
| // This file is loaded into the same scope as subprocess_win.jsm
 | |
| /* import-globals-from subprocess_win.jsm */
 | |
| 
 | |
| const LIBC = OS.Constants.libc;
 | |
| 
 | |
| const Win = OS.Constants.Win;
 | |
| 
 | |
| const LIBC_CHOICES = ["kernel32.dll"];
 | |
| 
 | |
| var win32 = {
 | |
|   // On Windows 64, winapi_abi is an alias for default_abi.
 | |
|   WINAPI: ctypes.winapi_abi,
 | |
| 
 | |
|   VOID: ctypes.void_t,
 | |
| 
 | |
|   BYTE: ctypes.uint8_t,
 | |
|   WORD: ctypes.uint16_t,
 | |
|   DWORD: ctypes.uint32_t,
 | |
|   LONG: ctypes.long,
 | |
|   LARGE_INTEGER: ctypes.int64_t,
 | |
|   ULONGLONG: ctypes.uint64_t,
 | |
| 
 | |
|   UINT: ctypes.unsigned_int,
 | |
|   UCHAR: ctypes.unsigned_char,
 | |
| 
 | |
|   BOOL: ctypes.bool,
 | |
| 
 | |
|   HANDLE: ctypes.voidptr_t,
 | |
|   PVOID: ctypes.voidptr_t,
 | |
|   LPVOID: ctypes.voidptr_t,
 | |
| 
 | |
|   CHAR: ctypes.char,
 | |
|   WCHAR: ctypes.jschar,
 | |
| 
 | |
|   ULONG_PTR: ctypes.uintptr_t,
 | |
| 
 | |
|   SIZE_T: ctypes.size_t,
 | |
|   PSIZE_T: ctypes.size_t.ptr,
 | |
| };
 | |
| 
 | |
| Object.assign(win32, {
 | |
|   DWORD_PTR: win32.ULONG_PTR,
 | |
| 
 | |
|   LPSTR: win32.CHAR.ptr,
 | |
|   LPWSTR: win32.WCHAR.ptr,
 | |
| 
 | |
|   LPBYTE: win32.BYTE.ptr,
 | |
|   LPDWORD: win32.DWORD.ptr,
 | |
|   LPHANDLE: win32.HANDLE.ptr,
 | |
| 
 | |
|   // This is an opaque type.
 | |
|   PROC_THREAD_ATTRIBUTE_LIST: ctypes.char.array(),
 | |
|   LPPROC_THREAD_ATTRIBUTE_LIST: ctypes.char.ptr,
 | |
| });
 | |
| 
 | |
| Object.assign(win32, {
 | |
|   LPCSTR: win32.LPSTR,
 | |
|   LPCWSTR: win32.LPWSTR,
 | |
|   LPCVOID: win32.LPVOID,
 | |
| });
 | |
| 
 | |
| Object.assign(win32, {
 | |
|   INVALID_HANDLE_VALUE: ctypes.cast(ctypes.int64_t(-1), win32.HANDLE),
 | |
|   NULL_HANDLE_VALUE: ctypes.cast(ctypes.uintptr_t(0), win32.HANDLE),
 | |
| 
 | |
|   CREATE_SUSPENDED: 0x00000004,
 | |
|   CREATE_NEW_CONSOLE: 0x00000010,
 | |
|   CREATE_UNICODE_ENVIRONMENT: 0x00000400,
 | |
|   CREATE_NO_WINDOW: 0x08000000,
 | |
|   CREATE_BREAKAWAY_FROM_JOB: 0x01000000,
 | |
|   EXTENDED_STARTUPINFO_PRESENT: 0x00080000,
 | |
| 
 | |
|   STARTF_USESTDHANDLES: 0x0100,
 | |
| 
 | |
|   DUPLICATE_CLOSE_SOURCE: 0x01,
 | |
|   DUPLICATE_SAME_ACCESS: 0x02,
 | |
| 
 | |
|   ERROR_HANDLE_EOF: 38,
 | |
|   ERROR_BROKEN_PIPE: 109,
 | |
|   ERROR_INSUFFICIENT_BUFFER: 122,
 | |
| 
 | |
|   FILE_FLAG_OVERLAPPED: 0x40000000,
 | |
| 
 | |
|   PIPE_TYPE_BYTE: 0x00,
 | |
| 
 | |
|   PIPE_ACCESS_INBOUND: 0x01,
 | |
|   PIPE_ACCESS_OUTBOUND: 0x02,
 | |
|   PIPE_ACCESS_DUPLEX: 0x03,
 | |
| 
 | |
|   PIPE_WAIT: 0x00,
 | |
|   PIPE_NOWAIT: 0x01,
 | |
| 
 | |
|   STILL_ACTIVE: 259,
 | |
| 
 | |
|   PROC_THREAD_ATTRIBUTE_HANDLE_LIST: 0x00020002,
 | |
| 
 | |
|   JobObjectBasicLimitInformation: 2,
 | |
|   JobObjectExtendedLimitInformation: 9,
 | |
| 
 | |
|   JOB_OBJECT_LIMIT_BREAKAWAY_OK: 0x00000800,
 | |
| 
 | |
|   // These constants are 32-bit unsigned integers, but Windows defines
 | |
|   // them as negative integers cast to an unsigned type.
 | |
|   STD_INPUT_HANDLE: -10 + 0x100000000,
 | |
|   STD_OUTPUT_HANDLE: -11 + 0x100000000,
 | |
|   STD_ERROR_HANDLE: -12 + 0x100000000,
 | |
| 
 | |
|   WAIT_TIMEOUT: 0x00000102,
 | |
|   WAIT_FAILED: 0xffffffff,
 | |
| });
 | |
| 
 | |
| Object.assign(win32, {
 | |
|   JOBOBJECT_BASIC_LIMIT_INFORMATION: new ctypes.StructType(
 | |
|     "JOBOBJECT_BASIC_LIMIT_INFORMATION",
 | |
|     [
 | |
|       { PerProcessUserTimeLimit: win32.LARGE_INTEGER },
 | |
|       { PerJobUserTimeLimit: win32.LARGE_INTEGER },
 | |
|       { LimitFlags: win32.DWORD },
 | |
|       { MinimumWorkingSetSize: win32.SIZE_T },
 | |
|       { MaximumWorkingSetSize: win32.SIZE_T },
 | |
|       { ActiveProcessLimit: win32.DWORD },
 | |
|       { Affinity: win32.ULONG_PTR },
 | |
|       { PriorityClass: win32.DWORD },
 | |
|       { SchedulingClass: win32.DWORD },
 | |
|     ]
 | |
|   ),
 | |
| 
 | |
|   IO_COUNTERS: new ctypes.StructType("IO_COUNTERS", [
 | |
|     { ReadOperationCount: win32.ULONGLONG },
 | |
|     { WriteOperationCount: win32.ULONGLONG },
 | |
|     { OtherOperationCount: win32.ULONGLONG },
 | |
|     { ReadTransferCount: win32.ULONGLONG },
 | |
|     { WriteTransferCount: win32.ULONGLONG },
 | |
|     { OtherTransferCount: win32.ULONGLONG },
 | |
|   ]),
 | |
| });
 | |
| 
 | |
| Object.assign(win32, {
 | |
|   JOBOBJECT_EXTENDED_LIMIT_INFORMATION: new ctypes.StructType(
 | |
|     "JOBOBJECT_EXTENDED_LIMIT_INFORMATION",
 | |
|     [
 | |
|       { BasicLimitInformation: win32.JOBOBJECT_BASIC_LIMIT_INFORMATION },
 | |
|       { IoInfo: win32.IO_COUNTERS },
 | |
|       { ProcessMemoryLimit: win32.SIZE_T },
 | |
|       { JobMemoryLimit: win32.SIZE_T },
 | |
|       { PeakProcessMemoryUsed: win32.SIZE_T },
 | |
|       { PeakJobMemoryUsed: win32.SIZE_T },
 | |
|     ]
 | |
|   ),
 | |
| 
 | |
|   OVERLAPPED: new ctypes.StructType("OVERLAPPED", [
 | |
|     { Internal: win32.ULONG_PTR },
 | |
|     { InternalHigh: win32.ULONG_PTR },
 | |
|     { Offset: win32.DWORD },
 | |
|     { OffsetHigh: win32.DWORD },
 | |
|     { hEvent: win32.HANDLE },
 | |
|   ]),
 | |
| 
 | |
|   PROCESS_INFORMATION: new ctypes.StructType("PROCESS_INFORMATION", [
 | |
|     { hProcess: win32.HANDLE },
 | |
|     { hThread: win32.HANDLE },
 | |
|     { dwProcessId: win32.DWORD },
 | |
|     { dwThreadId: win32.DWORD },
 | |
|   ]),
 | |
| 
 | |
|   SECURITY_ATTRIBUTES: new ctypes.StructType("SECURITY_ATTRIBUTES", [
 | |
|     { nLength: win32.DWORD },
 | |
|     { lpSecurityDescriptor: win32.LPVOID },
 | |
|     { bInheritHandle: win32.BOOL },
 | |
|   ]),
 | |
| 
 | |
|   STARTUPINFOW: new ctypes.StructType("STARTUPINFOW", [
 | |
|     { cb: win32.DWORD },
 | |
|     { lpReserved: win32.LPWSTR },
 | |
|     { lpDesktop: win32.LPWSTR },
 | |
|     { lpTitle: win32.LPWSTR },
 | |
|     { dwX: win32.DWORD },
 | |
|     { dwY: win32.DWORD },
 | |
|     { dwXSize: win32.DWORD },
 | |
|     { dwYSize: win32.DWORD },
 | |
|     { dwXCountChars: win32.DWORD },
 | |
|     { dwYCountChars: win32.DWORD },
 | |
|     { dwFillAttribute: win32.DWORD },
 | |
|     { dwFlags: win32.DWORD },
 | |
|     { wShowWindow: win32.WORD },
 | |
|     { cbReserved2: win32.WORD },
 | |
|     { lpReserved2: win32.LPBYTE },
 | |
|     { hStdInput: win32.HANDLE },
 | |
|     { hStdOutput: win32.HANDLE },
 | |
|     { hStdError: win32.HANDLE },
 | |
|   ]),
 | |
| });
 | |
| 
 | |
| Object.assign(win32, {
 | |
|   STARTUPINFOEXW: new ctypes.StructType("STARTUPINFOEXW", [
 | |
|     { StartupInfo: win32.STARTUPINFOW },
 | |
|     { lpAttributeList: win32.LPPROC_THREAD_ATTRIBUTE_LIST },
 | |
|   ]),
 | |
| });
 | |
| 
 | |
| var libc = new Library("libc", LIBC_CHOICES, {
 | |
|   AssignProcessToJobObject: [
 | |
|     win32.WINAPI,
 | |
|     win32.BOOL,
 | |
|     win32.HANDLE /* hJob */,
 | |
|     win32.HANDLE /* hProcess */,
 | |
|   ],
 | |
| 
 | |
|   CloseHandle: [win32.WINAPI, win32.BOOL, win32.HANDLE /* hObject */],
 | |
| 
 | |
|   CreateEventW: [
 | |
|     win32.WINAPI,
 | |
|     win32.HANDLE,
 | |
|     win32.SECURITY_ATTRIBUTES.ptr /* opt lpEventAttributes */,
 | |
|     win32.BOOL /* bManualReset */,
 | |
|     win32.BOOL /* bInitialState */,
 | |
|     win32.LPWSTR /* lpName */,
 | |
|   ],
 | |
| 
 | |
|   CreateFileW: [
 | |
|     win32.WINAPI,
 | |
|     win32.HANDLE,
 | |
|     win32.LPWSTR /* lpFileName */,
 | |
|     win32.DWORD /* dwDesiredAccess */,
 | |
|     win32.DWORD /* dwShareMode */,
 | |
|     win32.SECURITY_ATTRIBUTES.ptr /* opt lpSecurityAttributes */,
 | |
|     win32.DWORD /* dwCreationDisposition */,
 | |
|     win32.DWORD /* dwFlagsAndAttributes */,
 | |
|     win32.HANDLE /* opt hTemplateFile */,
 | |
|   ],
 | |
| 
 | |
|   CreateJobObjectW: [
 | |
|     win32.WINAPI,
 | |
|     win32.HANDLE,
 | |
|     win32.SECURITY_ATTRIBUTES.ptr /* opt lpJobAttributes */,
 | |
|     win32.LPWSTR /* lpName */,
 | |
|   ],
 | |
| 
 | |
|   CreateNamedPipeW: [
 | |
|     win32.WINAPI,
 | |
|     win32.HANDLE,
 | |
|     win32.LPWSTR /* lpName */,
 | |
|     win32.DWORD /* dwOpenMode */,
 | |
|     win32.DWORD /* dwPipeMode */,
 | |
|     win32.DWORD /* nMaxInstances */,
 | |
|     win32.DWORD /* nOutBufferSize */,
 | |
|     win32.DWORD /* nInBufferSize */,
 | |
|     win32.DWORD /* nDefaultTimeOut */,
 | |
|     win32.SECURITY_ATTRIBUTES.ptr /* opt lpSecurityAttributes */,
 | |
|   ],
 | |
| 
 | |
|   CreatePipe: [
 | |
|     win32.WINAPI,
 | |
|     win32.BOOL,
 | |
|     win32.LPHANDLE /* out hReadPipe */,
 | |
|     win32.LPHANDLE /* out hWritePipe */,
 | |
|     win32.SECURITY_ATTRIBUTES.ptr /* opt lpPipeAttributes */,
 | |
|     win32.DWORD /* nSize */,
 | |
|   ],
 | |
| 
 | |
|   CreateProcessW: [
 | |
|     win32.WINAPI,
 | |
|     win32.BOOL,
 | |
|     win32.LPCWSTR /* lpApplicationName */,
 | |
|     win32.LPWSTR /* lpCommandLine */,
 | |
|     win32.SECURITY_ATTRIBUTES.ptr /* lpProcessAttributes */,
 | |
|     win32.SECURITY_ATTRIBUTES.ptr /* lpThreadAttributes */,
 | |
|     win32.BOOL /* bInheritHandle */,
 | |
|     win32.DWORD /* dwCreationFlags */,
 | |
|     win32.LPVOID /* opt lpEnvironment */,
 | |
|     win32.LPCWSTR /* opt lpCurrentDirectory */,
 | |
|     win32.STARTUPINFOW.ptr /* lpStartupInfo */,
 | |
|     win32.PROCESS_INFORMATION.ptr /* out lpProcessInformation */,
 | |
|   ],
 | |
| 
 | |
|   CreateSemaphoreW: [
 | |
|     win32.WINAPI,
 | |
|     win32.HANDLE,
 | |
|     win32.SECURITY_ATTRIBUTES.ptr /* opt lpSemaphoreAttributes */,
 | |
|     win32.LONG /* lInitialCount */,
 | |
|     win32.LONG /* lMaximumCount */,
 | |
|     win32.LPCWSTR /* opt lpName */,
 | |
|   ],
 | |
| 
 | |
|   DeleteProcThreadAttributeList: [
 | |
|     win32.WINAPI,
 | |
|     win32.VOID,
 | |
|     win32.LPPROC_THREAD_ATTRIBUTE_LIST /* in/out lpAttributeList */,
 | |
|   ],
 | |
| 
 | |
|   DuplicateHandle: [
 | |
|     win32.WINAPI,
 | |
|     win32.BOOL,
 | |
|     win32.HANDLE /* hSourceProcessHandle */,
 | |
|     win32.HANDLE /* hSourceHandle */,
 | |
|     win32.HANDLE /* hTargetProcessHandle */,
 | |
|     win32.LPHANDLE /* out lpTargetHandle */,
 | |
|     win32.DWORD /* dwDesiredAccess */,
 | |
|     win32.BOOL /* bInheritHandle */,
 | |
|     win32.DWORD /* dwOptions */,
 | |
|   ],
 | |
| 
 | |
|   FreeEnvironmentStringsW: [
 | |
|     win32.WINAPI,
 | |
|     win32.BOOL,
 | |
|     win32.LPCWSTR /* lpszEnvironmentBlock */,
 | |
|   ],
 | |
| 
 | |
|   GetCurrentProcess: [win32.WINAPI, win32.HANDLE],
 | |
| 
 | |
|   GetCurrentProcessId: [win32.WINAPI, win32.DWORD],
 | |
| 
 | |
|   GetEnvironmentStringsW: [win32.WINAPI, win32.LPCWSTR],
 | |
| 
 | |
|   GetExitCodeProcess: [
 | |
|     win32.WINAPI,
 | |
|     win32.BOOL,
 | |
|     win32.HANDLE /* hProcess */,
 | |
|     win32.LPDWORD /* lpExitCode */,
 | |
|   ],
 | |
| 
 | |
|   GetOverlappedResult: [
 | |
|     win32.WINAPI,
 | |
|     win32.BOOL,
 | |
|     win32.HANDLE /* hFile */,
 | |
|     win32.OVERLAPPED.ptr /* lpOverlapped */,
 | |
|     win32.LPDWORD /* lpNumberOfBytesTransferred */,
 | |
|     win32.BOOL /* bWait */,
 | |
|   ],
 | |
| 
 | |
|   GetStdHandle: [win32.WINAPI, win32.HANDLE, win32.DWORD /* nStdHandle */],
 | |
| 
 | |
|   InitializeProcThreadAttributeList: [
 | |
|     win32.WINAPI,
 | |
|     win32.BOOL,
 | |
|     win32.LPPROC_THREAD_ATTRIBUTE_LIST /* out opt lpAttributeList */,
 | |
|     win32.DWORD /* dwAttributeCount */,
 | |
|     win32.DWORD /* dwFlags */,
 | |
|     win32.PSIZE_T /* in/out lpSize */,
 | |
|   ],
 | |
| 
 | |
|   ReadFile: [
 | |
|     win32.WINAPI,
 | |
|     win32.BOOL,
 | |
|     win32.HANDLE /* hFile */,
 | |
|     win32.LPVOID /* out lpBuffer */,
 | |
|     win32.DWORD /* nNumberOfBytesToRead */,
 | |
|     win32.LPDWORD /* opt out lpNumberOfBytesRead */,
 | |
|     win32.OVERLAPPED.ptr /* opt in/out lpOverlapped */,
 | |
|   ],
 | |
| 
 | |
|   ReleaseSemaphore: [
 | |
|     win32.WINAPI,
 | |
|     win32.BOOL,
 | |
|     win32.HANDLE /* hSemaphore */,
 | |
|     win32.LONG /* lReleaseCount */,
 | |
|     win32.LONG.ptr /* opt out lpPreviousCount */,
 | |
|   ],
 | |
| 
 | |
|   ResumeThread: [win32.WINAPI, win32.DWORD, win32.HANDLE /* hThread */],
 | |
| 
 | |
|   SetInformationJobObject: [
 | |
|     win32.WINAPI,
 | |
|     win32.BOOL,
 | |
|     win32.HANDLE /* hJob */,
 | |
|     ctypes.int /* JobObjectInfoClass */,
 | |
|     win32.LPVOID /* lpJobObjectInfo */,
 | |
|     win32.DWORD /* cbJobObjectInfoLengt */,
 | |
|   ],
 | |
| 
 | |
|   TerminateJobObject: [
 | |
|     win32.WINAPI,
 | |
|     win32.BOOL,
 | |
|     win32.HANDLE /* hJob */,
 | |
|     win32.UINT /* uExitCode */,
 | |
|   ],
 | |
| 
 | |
|   TerminateProcess: [
 | |
|     win32.WINAPI,
 | |
|     win32.BOOL,
 | |
|     win32.HANDLE /* hProcess */,
 | |
|     win32.UINT /* uExitCode */,
 | |
|   ],
 | |
| 
 | |
|   UpdateProcThreadAttribute: [
 | |
|     win32.WINAPI,
 | |
|     win32.BOOL,
 | |
|     win32.LPPROC_THREAD_ATTRIBUTE_LIST /* in/out lpAttributeList */,
 | |
|     win32.DWORD /* dwFlags */,
 | |
|     win32.DWORD_PTR /* Attribute */,
 | |
|     win32.PVOID /* lpValue */,
 | |
|     win32.SIZE_T /* cbSize */,
 | |
|     win32.PVOID /* out opt lpPreviousValue */,
 | |
|     win32.PSIZE_T /* opt lpReturnSize */,
 | |
|   ],
 | |
| 
 | |
|   WaitForMultipleObjects: [
 | |
|     win32.WINAPI,
 | |
|     win32.DWORD,
 | |
|     win32.DWORD /* nCount */,
 | |
|     win32.HANDLE.ptr /* hHandles */,
 | |
|     win32.BOOL /* bWaitAll */,
 | |
|     win32.DWORD /* dwMilliseconds */,
 | |
|   ],
 | |
| 
 | |
|   WaitForSingleObject: [
 | |
|     win32.WINAPI,
 | |
|     win32.DWORD,
 | |
|     win32.HANDLE /* hHandle */,
 | |
|     win32.BOOL /* bWaitAll */,
 | |
|     win32.DWORD /* dwMilliseconds */,
 | |
|   ],
 | |
| 
 | |
|   WriteFile: [
 | |
|     win32.WINAPI,
 | |
|     win32.BOOL,
 | |
|     win32.HANDLE /* hFile */,
 | |
|     win32.LPCVOID /* lpBuffer */,
 | |
|     win32.DWORD /* nNumberOfBytesToRead */,
 | |
|     win32.LPDWORD /* opt out lpNumberOfBytesWritten */,
 | |
|     win32.OVERLAPPED.ptr /* opt in/out lpOverlapped */,
 | |
|   ],
 | |
| });
 | |
| 
 | |
| let nextNamedPipeId = 0;
 | |
| 
 | |
| win32.Handle = function(handle) {
 | |
|   return ctypes.CDataFinalizer(win32.HANDLE(handle), libc.CloseHandle);
 | |
| };
 | |
| 
 | |
| win32.createPipe = function(secAttr, readFlags = 0, writeFlags = 0, size = 0) {
 | |
|   readFlags |= win32.PIPE_ACCESS_INBOUND;
 | |
|   writeFlags |= Win.FILE_ATTRIBUTE_NORMAL;
 | |
| 
 | |
|   if (size == 0) {
 | |
|     size = 4096;
 | |
|   }
 | |
| 
 | |
|   let pid = libc.GetCurrentProcessId();
 | |
|   let pipeName = String.raw`\\.\Pipe\SubProcessPipe.${pid}.${nextNamedPipeId++}`;
 | |
| 
 | |
|   let readHandle = libc.CreateNamedPipeW(
 | |
|     pipeName,
 | |
|     readFlags,
 | |
|     win32.PIPE_TYPE_BYTE | win32.PIPE_WAIT,
 | |
|     1 /* number of connections */,
 | |
|     size /* output buffer size */,
 | |
|     size /* input buffer size */,
 | |
|     0 /* timeout */,
 | |
|     secAttr.address()
 | |
|   );
 | |
| 
 | |
|   let isInvalid = handle =>
 | |
|     String(handle) == String(win32.HANDLE(Win.INVALID_HANDLE_VALUE));
 | |
| 
 | |
|   if (isInvalid(readHandle)) {
 | |
|     return [];
 | |
|   }
 | |
| 
 | |
|   let writeHandle = libc.CreateFileW(
 | |
|     pipeName,
 | |
|     Win.GENERIC_WRITE,
 | |
|     0,
 | |
|     secAttr.address(),
 | |
|     Win.OPEN_EXISTING,
 | |
|     writeFlags,
 | |
|     null
 | |
|   );
 | |
| 
 | |
|   if (isInvalid(writeHandle)) {
 | |
|     libc.CloseHandle(readHandle);
 | |
|     return [];
 | |
|   }
 | |
| 
 | |
|   return [win32.Handle(readHandle), win32.Handle(writeHandle)];
 | |
| };
 | |
| 
 | |
| win32.createThreadAttributeList = function(handles) {
 | |
|   try {
 | |
|     void libc.InitializeProcThreadAttributeList;
 | |
|     void libc.DeleteProcThreadAttributeList;
 | |
|     void libc.UpdateProcThreadAttribute;
 | |
|   } catch (e) {
 | |
|     // This is only supported in Windows Vista and later.
 | |
|     return null;
 | |
|   }
 | |
| 
 | |
|   let size = win32.SIZE_T();
 | |
|   if (
 | |
|     !libc.InitializeProcThreadAttributeList(null, 1, 0, size.address()) &&
 | |
|     ctypes.winLastError != win32.ERROR_INSUFFICIENT_BUFFER
 | |
|   ) {
 | |
|     return null;
 | |
|   }
 | |
| 
 | |
|   let attrList = win32.PROC_THREAD_ATTRIBUTE_LIST(size.value);
 | |
| 
 | |
|   if (!libc.InitializeProcThreadAttributeList(attrList, 1, 0, size.address())) {
 | |
|     return null;
 | |
|   }
 | |
| 
 | |
|   let ok = libc.UpdateProcThreadAttribute(
 | |
|     attrList,
 | |
|     0,
 | |
|     win32.PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
 | |
|     handles,
 | |
|     handles.constructor.size,
 | |
|     null,
 | |
|     null
 | |
|   );
 | |
| 
 | |
|   if (!ok) {
 | |
|     libc.DeleteProcThreadAttributeList(attrList);
 | |
|     return null;
 | |
|   }
 | |
| 
 | |
|   return attrList;
 | |
| };
 |