diff --git a/toolkit/modules/subprocess/subprocess_shared_win.js b/toolkit/modules/subprocess/subprocess_shared_win.js index 6b666ece629a..6267b8cc73a8 100644 --- a/toolkit/modules/subprocess/subprocess_shared_win.js +++ b/toolkit/modules/subprocess/subprocess_shared_win.js @@ -23,6 +23,8 @@ var win32 = { 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, @@ -95,6 +97,11 @@ Object.assign(win32, { 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, @@ -106,6 +113,38 @@ Object.assign(win32, { }); 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}, @@ -339,6 +378,15 @@ var libc = new Library("libc", LIBC_CHOICES, { 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, diff --git a/toolkit/modules/subprocess/subprocess_worker_win.js b/toolkit/modules/subprocess/subprocess_worker_win.js index b0756dac344e..1db71514dfdc 100644 --- a/toolkit/modules/subprocess/subprocess_worker_win.js +++ b/toolkit/modules/subprocess/subprocess_worker_win.js @@ -499,6 +499,17 @@ class Process extends BaseProcess { if (ok) { this.jobHandle = win32.Handle(libc.CreateJobObjectW(null, null)); + + let info = win32.JOBOBJECT_EXTENDED_LIMIT_INFORMATION(); + info.BasicLimitInformation.LimitFlags = win32.JOB_OBJECT_LIMIT_BREAKAWAY_OK; + + ok = libc.SetInformationJobObject(this.jobHandle, win32.JobObjectExtendedLimitInformation, + ctypes.cast(info.address(), ctypes.voidptr_t), + info.constructor.size); + errorMessage = `Failed to set job limits: 0x${(ctypes.winLastError || 0).toString(16)}`; + } + + if (ok) { ok = libc.AssignProcessToJobObject(this.jobHandle, procInfo.hProcess); errorMessage = `Failed to attach process to job object: 0x${(ctypes.winLastError || 0).toString(16)}`; }