Bug 1301246: Allow processes to break away from their job. r?mhowell draft
authorKris Maglione <maglione.k@gmail.com>
Thu, 08 Sep 2016 12:26:13 -0700
changeset 411810 2c69ad905111bfe2f48bbfd8c07df4b834194d39
parent 411809 e8563d2b4b656b41c65e00dc654df5eadca6b2e5
child 530829 4ec287a0460ba6758a78213711849fb2a995a337
push id28998
push usermaglione.k@gmail.com
push dateThu, 08 Sep 2016 20:59:13 +0000
reviewersmhowell
bugs1301246
milestone51.0a1
Bug 1301246: Allow processes to break away from their job. r?mhowell MozReview-Commit-ID: IFyK7HkQP35
toolkit/modules/subprocess/subprocess_shared_win.js
toolkit/modules/subprocess/subprocess_worker_win.js
--- a/toolkit/modules/subprocess/subprocess_shared_win.js
+++ b/toolkit/modules/subprocess/subprocess_shared_win.js
@@ -18,16 +18,19 @@ var win32 = {
   WINAPI: ctypes.winapi_abi,
 
   VOID: ctypes.void_t,
 
   BYTE: ctypes.uint8_t,
   WORD: ctypes.uint16_t,
   DWORD: ctypes.uint32_t,
   LONG: ctypes.long,
+  LONGLONG: ctypes.int64_t,
+  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,
@@ -90,27 +93,64 @@ Object.assign(win32, {
 
   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},
   ]),
 
@@ -334,16 +374,25 @@ var libc = new Library("libc", LIBC_CHOI
   ],
 
   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: [
--- a/toolkit/modules/subprocess/subprocess_worker_win.js
+++ b/toolkit/modules/subprocess/subprocess_worker_win.js
@@ -494,16 +494,27 @@ class Process extends BaseProcess {
     }
 
     if (threadAttrs) {
       libc.DeleteProcThreadAttributeList(threadAttrs);
     }
 
     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)}`;
     }
 
     if (!ok) {
       for (let pipe of this.pipes) {
         pipe.close();
       }