diff --git a/client/app_start.cpp b/client/app_start.cpp
index 2137d4750f..2f9c44ab6a 100644
--- a/client/app_start.cpp
+++ b/client/app_start.cpp
@@ -84,7 +84,7 @@ using std::string;
#ifdef _WIN32
-#include "proc_control.h"
+#include "run_app_windows.h"
#endif
#include "cs_proxy.h"
diff --git a/client/client_state.cpp b/client/client_state.cpp
index acbe17839e..1a59d49a90 100644
--- a/client/client_state.cpp
+++ b/client/client_state.cpp
@@ -44,7 +44,7 @@
#include "error_numbers.h"
#include "filesys.h"
#ifdef _WIN32
-#include "proc_control.h"
+#include "run_app_windows.h"
#endif
#include "file_names.h"
diff --git a/lib/proc_control.cpp b/lib/proc_control.cpp
index a9d7cff358..40a55dbbef 100644
--- a/lib/proc_control.cpp
+++ b/lib/proc_control.cpp
@@ -1,195 +1,209 @@
-// This file is part of BOINC.
-// http://boinc.berkeley.edu
-// Copyright (C) 2011 University of California
-//
-// BOINC is free software; you can redistribute it and/or modify it
-// under the terms of the GNU Lesser General Public License
-// as published by the Free Software Foundation,
-// either version 3 of the License, or (at your option) any later version.
-//
-// BOINC is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-// See the GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with BOINC. If not, see .
-
-#include
-#include
-#include
-#include
-
-#include "procinfo.h"
-
-#include "proc_control.h"
-
-using std::vector;
-
-static void get_descendants_aux(PROC_MAP& pm, int pid, vector& pids) {
- PROC_MAP::iterator i = pm.find(pid);
- if (i == pm.end()) return;
- for (unsigned int j=0; jsecond.children.size(); j++) {
- int child_pid = i->second.children[j];
- pids.push_back(child_pid);
- get_descendants_aux(pm, child_pid, pids);
- }
-}
-
-// return a list of all descendants of the given process
-//
-void get_descendants(int pid, vector& pids) {
- int retval;
- PROC_MAP pm;
- pids.clear();
- retval = procinfo_setup(pm);
- if (retval) return;
- get_descendants_aux(pm, pid, pids);
-}
-
-bool any_process_exists(vector& pids) {
- int status;
- for (unsigned int i=0; i= 0) {
- return true;
- }
- }
- return false;
-}
-
-void kill_all(vector& pids) {
- for (unsigned int i=0; i descendants;
- // on Win, kill descendants directly
- //
- get_descendants(GetCurrentProcessId(), descendants);
- kill_all(descendants);
-}
-#else
-// Same, but if child_pid is nonzero, give it a chance to exit gracefully on Unix
-//
-void kill_descendants(int child_pid) {
- vector descendants;
- // on Unix, ask main process nicely.
- // it descendants still exist after 10 sec, use the nuclear option
- //
- get_descendants(getpid(), descendants);
- if (child_pid) {
- ::kill(child_pid, SIGTERM);
- for (int i=0; i<10; i++) {
- if (!any_process_exists(descendants)) {
- return;
- }
- sleep(1);
- }
- kill_all(descendants);
- // kill any processes that might have been created
- // in the last 10 secs
- get_descendants(getpid(), descendants);
- }
- kill_all(descendants);
-}
-#endif
-
-void suspend_or_resume_all(vector& pids, bool resume) {
- for (unsigned int i=0; i descendants;
- if (!pid) {
-#ifdef _WIN32
- pid = GetCurrentProcessId();
-#else
- pid = getpid();
-#endif
- }
- get_descendants(pid, descendants);
- suspend_or_resume_all(descendants, resume);
-}
-
-void suspend_or_resume_process(int pid, bool resume) {
-#ifdef _WIN32
- suspend_or_resume_threads(pid, 0, resume);
-#else
- ::kill(pid, resume?SIGCONT:SIGSTOP);
-#endif
-
-}
+// This file is part of BOINC.
+// http://boinc.berkeley.edu
+// Copyright (C) 2011 University of California
+//
+// BOINC is free software; you can redistribute it and/or modify it
+// under the terms of the GNU Lesser General Public License
+// as published by the Free Software Foundation,
+// either version 3 of the License, or (at your option) any later version.
+//
+// BOINC is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+// See the GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with BOINC. If not, see .
+
+#include
+#ifdef _WIN32
+#include "diagnostics.h"
+#ifdef __STDWX_H__
+#include "stdwx.h"
+#else
+#include "boinc_win.h"
+#include "win_util.h"
+#endif
+#else
+#include
+#include
+#include
+#endif
+
+#include "procinfo.h"
+
+#include "proc_control.h"
+
+using std::vector;
+
+static void get_descendants_aux(PROC_MAP& pm, int pid, vector& pids) {
+ PROC_MAP::iterator i = pm.find(pid);
+ if (i == pm.end()) return;
+ for (unsigned int j=0; jsecond.children.size(); j++) {
+ int child_pid = i->second.children[j];
+ pids.push_back(child_pid);
+ get_descendants_aux(pm, child_pid, pids);
+ }
+}
+
+// return a list of all descendants of the given process
+//
+void get_descendants(int pid, vector& pids) {
+ int retval;
+ PROC_MAP pm;
+ pids.clear();
+ retval = procinfo_setup(pm);
+ if (retval) return;
+ get_descendants_aux(pm, pid, pids);
+}
+
+#ifdef _WIN32
+// signature of OpenThread()
+//
+typedef HANDLE (WINAPI *tOT)(
+ DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId
+);
+
+// Suspend or resume the threads in a given process,
+// but don't suspend 'calling_thread'.
+//
+// The only way to do this on Windows is to enumerate
+// all the threads in the entire system,
+// and find those belonging to the process (ugh!!)
+//
+
+int suspend_or_resume_threads(
+ DWORD pid, DWORD calling_thread_id, bool resume
+) {
+ HANDLE threads, thread;
+ static HMODULE hKernel32Lib = NULL;
+ THREADENTRY32 te = {0};
+ static tOT pOT = NULL;
+
+ // Dynamically link to the proper function pointers.
+ if (!hKernel32Lib) {
+ hKernel32Lib = GetModuleHandleA("kernel32.dll");
+ }
+ if (!pOT) {
+ pOT = (tOT) GetProcAddress( hKernel32Lib, "OpenThread" );
+ }
+
+ if (!pOT) {
+ return -1;
+ }
+
+ threads = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
+ if (threads == INVALID_HANDLE_VALUE) return -1;
+
+ te.dwSize = sizeof(THREADENTRY32);
+ if (!Thread32First(threads, &te)) {
+ CloseHandle(threads);
+ return -1;
+ }
+
+ do {
+ if (!diagnostics_is_thread_exempt_suspend(te.th32ThreadID)) continue;
+ if (te.th32ThreadID == calling_thread_id) continue;
+ if (te.th32OwnerProcessID == pid) {
+ thread = pOT(THREAD_SUSPEND_RESUME, FALSE, te.th32ThreadID);
+ resume ? ResumeThread(thread) : SuspendThread(thread);
+ CloseHandle(thread);
+ }
+ } while (Thread32Next(threads, &te));
+
+ CloseHandle (threads);
+
+ return 0;
+}
+
+#else
+
+bool any_process_exists(vector& pids) {
+ int status;
+ for (unsigned int i=0; i= 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void kill_all(vector& pids) {
+ for (unsigned int i=0; i descendants;
+ // on Win, kill descendants directly
+ //
+ get_descendants(GetCurrentProcessId(), descendants);
+ kill_all(descendants);
+}
+#else
+// Same, but if child_pid is nonzero, give it a chance to exit gracefully on Unix
+//
+void kill_descendants(int child_pid) {
+ vector descendants;
+ // on Unix, ask main process nicely.
+ // it descendants still exist after 10 sec, use the nuclear option
+ //
+ get_descendants(getpid(), descendants);
+ if (child_pid) {
+ ::kill(child_pid, SIGTERM);
+ for (int i=0; i<10; i++) {
+ if (!any_process_exists(descendants)) {
+ return;
+ }
+ sleep(1);
+ }
+ kill_all(descendants);
+ // kill any processes that might have been created
+ // in the last 10 secs
+ get_descendants(getpid(), descendants);
+ }
+ kill_all(descendants);
+}
+#endif
+
+void suspend_or_resume_all(vector& pids, bool resume) {
+ for (unsigned int i=0; i descendants;
+ if (!pid) {
+#ifdef _WIN32
+ pid = GetCurrentProcessId();
+#else
+ pid = getpid();
+#endif
+ }
+ get_descendants(pid, descendants);
+ suspend_or_resume_all(descendants, resume);
+}
+
+void suspend_or_resume_process(int pid, bool resume) {
+#ifdef _WIN32
+ suspend_or_resume_threads(pid, 0, resume);
+#else
+ ::kill(pid, resume?SIGCONT:SIGSTOP);
+#endif
+
+}
diff --git a/samples/wrapper/wrapper.cpp b/samples/wrapper/wrapper.cpp
index 3cbe24de7b..b70850912b 100644
--- a/samples/wrapper/wrapper.cpp
+++ b/samples/wrapper/wrapper.cpp
@@ -41,7 +41,7 @@
#include
#endif
-#include "procinfo.h"
+#include "proc_control.h"
#include "boinc_api.h"
#include "diagnostics.h"
#include "filesys.h"
diff --git a/win_build/boinc_cli.vcproj b/win_build/boinc_cli.vcproj
index 610ef0c676..5d08bef9c4 100644
--- a/win_build/boinc_cli.vcproj
+++ b/win_build/boinc_cli.vcproj
@@ -735,6 +735,10 @@
RelativePath="..\client\rr_sim.cpp"
>
+
+
@@ -892,6 +896,10 @@
RelativePath="..\client\rr_sim.h"
>
+
+