diff --git a/checkin_notes b/checkin_notes
index 918c848533..e34eba6eb9 100644
--- a/checkin_notes
+++ b/checkin_notes
@@ -5137,3 +5137,12 @@ David 5 June 2009
sched/
sched_plan.cpp,h
+
+Charlie 5 June 2009
+ - MGR: Use code like get_client_mutex() to determine if client is running.
+ New CBOINCClientManager::KillClient() uses process name to kill client
+ if we don't have a pid (Mac, Linux) or process HANDLE (Windows).
+ NOTE: Windows implmentation not yet finished.
+
+ clientgui/
+ BOINCClientManager.cpp, .h
diff --git a/clientgui/BOINCClientManager.cpp b/clientgui/BOINCClientManager.cpp
index 6ca71fb4d3..980cb86b81 100644
--- a/clientgui/BOINCClientManager.cpp
+++ b/clientgui/BOINCClientManager.cpp
@@ -1,612 +1,448 @@
-// This file is part of BOINC.
-// http://boinc.berkeley.edu
-// Copyright (C) 2008 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 .
-
-#if defined(__GNUG__) && !defined(__APPLE__)
-#pragma implementation "BOINCClientManager.h"
-#endif
-
-#include "stdwx.h"
-#include "diagnostics.h"
-#include "LogBOINC.h"
-#include "BOINCGUIApp.h"
-#include "MainDocument.h"
-#include "BOINCBaseFrame.h"
-#include "AdvancedFrame.h"
-#include "BOINCClientManager.h"
-#include "error_numbers.h"
-
-#include "filesys.h"
-#include "util.h"
-
-#ifdef __WXMAC__
-enum {
- NewStyleDaemon = 1,
- OldStyleDaemon
-};
-#endif
-
-#ifdef __WXMSW__
-#include // for using bstr_t class
-
-EXTERN_C BOOL IsBOINCServiceInstalled();
-EXTERN_C BOOL IsBOINCServiceStarting();
-EXTERN_C BOOL IsBOINCServiceRunning();
-EXTERN_C BOOL IsBOINCServiceStopping();
-EXTERN_C BOOL IsBOINCServiceStopped();
-EXTERN_C BOOL StartBOINCService();
-EXTERN_C BOOL StopBOINCService();
-#endif
-
-CBOINCClientManager::CBOINCClientManager() {
- wxLogTrace(wxT("Function Start/End"), wxT("CBOINCClientManager::CBOINCClientManager - Function Begin"));
-
- m_bBOINCStartedByManager = false;
- m_lBOINCCoreProcessId = 0;
-
-#ifdef __WXMSW__
- m_hBOINCCoreProcess = NULL;
-#endif
-
- wxLogTrace(wxT("Function Start/End"), wxT("CBOINCClientManager::CBOINCClientManager - Function End"));
-}
-
-
-CBOINCClientManager::~CBOINCClientManager() {
- wxLogTrace(wxT("Function Start/End"), wxT("CBOINCClientManager::~CBOINCClientManager - Function Begin"));
-
- wxLogTrace(wxT("Function Start/End"), wxT("CBOINCClientManager::~CBOINCClientManager - Function End"));
-}
-
-
-bool CBOINCClientManager::AutoRestart() {
- if (IsBOINCCoreRunning()) return true;
-#ifndef __WXMAC__ // Mac can restart Client as a daemon
- if (! m_bBOINCStartedByManager) return false;
-#endif
- m_lBOINCCoreProcessId = 0;
- StartupBOINCCore();
- return true;
-}
-
-
-bool CBOINCClientManager::IsSystemBooting() {
- bool bReturnValue = false;
-#if defined(__WXMSW__)
- if (GetTickCount() < (1000*60*5)) bReturnValue = true; // If system has been up for less than 5 minutes
-#elif defined(__WXMAC__)
- if (TickCount() < (120*60)) bReturnValue = true; // If system has been up for less than 2 minutes
-#endif
- return bReturnValue;
-}
-
-
-int CBOINCClientManager::IsBOINCConfiguredAsDaemon() {
- bool bReturnValue = false;
-#if defined(__WXMSW__)
- if (IsBOINCServiceInstalled()) bReturnValue = 1;
-#elif defined(__WXMAC__)
- if ( boinc_file_exists("/Library/LaunchDaemons/edu.berkeley.boinc.plist")) {
- bReturnValue = NewStyleDaemon; // New-style daemon uses launchd
- }
- if (boinc_file_exists("/Library/StartupItems/boinc/boinc") ) {
- bReturnValue = OldStyleDaemon; // Old-style daemon uses StartupItem
- }
-#endif
- return bReturnValue;
-}
-
-
-bool CBOINCClientManager::IsBOINCCoreRunning() {
- wxLogTrace(wxT("Function Start/End"), wxT("CBOINCClientManager::IsBOINCCoreRunning - Function Begin"));
- bool running = false;
-
-#ifdef __WXMSW__
-
- if (IsBOINCServiceInstalled()) {
- running = (FALSE != IsBOINCServiceStarting()) || (FALSE != IsBOINCServiceRunning());
- } else {
- running = ProcessExists(&m_hBOINCCoreProcess);
- }
-#else
- running = ProcessExists(&m_lBOINCCoreProcessId);
-#endif
-
- wxLogTrace(wxT("Function Status"), wxT("CBOINCClientManager::IsBOINCCoreRunning - Returning '%d'"), (int)running);
- wxLogTrace(wxT("Function Start/End"), wxT("CBOINCClientManager::IsBOINCCoreRunning - Function End"));
- return running;
-}
-
-
-bool CBOINCClientManager::StartupBOINCCore() {
- wxLogTrace(wxT("Function Start/End"), wxT("CMainDocument::StartupBOINCCore - Function Begin"));
-
- bool bReturnValue = false;
- wxString strExecute = wxEmptyString;
-
- if (IsBOINCCoreRunning()) return true;
-
-#if defined(__WXMSW__)
- LPTSTR szExecute = NULL;
- LPTSTR szDataDirectory = NULL;
-
- if (IsBOINCConfiguredAsDaemon()) {
- StartBOINCService();
-
- m_bBOINCStartedByManager = true;
- bReturnValue = IsBOINCCoreRunning();
- } else {
-
- // Append boinc.exe to the end of the strExecute string and get ready to rock
- strExecute.Printf(
- wxT("\"%s\\boinc.exe\" --redirectio --launched_by_manager %s"),
- wxGetApp().GetRootDirectory().c_str(),
- wxGetApp().GetArguments().c_str()
- );
-
- PROCESS_INFORMATION pi;
- STARTUPINFO si;
- BOOL bProcessStarted;
-
- memset(&pi, 0, sizeof(pi));
- memset(&si, 0, sizeof(si));
-
- si.cb = sizeof(si);
- si.dwFlags = STARTF_USESHOWWINDOW;
- si.wShowWindow = SW_HIDE;
-
- szExecute = (LPTSTR)strExecute.c_str();
- if (wxGetApp().GetDataDirectory().empty()) {
- szDataDirectory = NULL;
- } else {
- szDataDirectory = (LPTSTR)wxGetApp().GetDataDirectory().c_str();
- }
-
- wxLogTrace(wxT("Function Status"), wxT("CMainDocument::StartupBOINCCore - szExecute '%s'\n"), szExecute);
- wxLogTrace(wxT("Function Status"), wxT("CMainDocument::StartupBOINCCore - szDataDirectory '%s'\n"), szDataDirectory);
-
- bProcessStarted = CreateProcess(
- NULL,
- szExecute,
- NULL,
- NULL,
- FALSE,
- CREATE_NEW_PROCESS_GROUP|CREATE_NO_WINDOW,
- NULL,
- szDataDirectory,
- &si,
- &pi
- );
-
- if (bProcessStarted) {
- m_lBOINCCoreProcessId = pi.dwProcessId;
- m_hBOINCCoreProcess = pi.hProcess;
- }
- }
-
-#elif defined(__WXMAC__)
-
-#if 0 // The Mac version of wxExecute(wxString& ...) crashes if there is a space in the path
- wxChar buf[1024];
- wxChar *argv[5];
-#else
- char buf[1024];
- char *argv[5];
-#endif
- ProcessSerialNumber ourPSN;
- FSRef ourFSRef;
- OSErr err;
-
- if (IsBOINCConfiguredAsDaemon() == NewStyleDaemon) {
- system ("launchctl load /Library/LaunchDaemons/edu.berkeley.boinc.plist");
- system ("launchctl start edu.berkeley.boinc");
- bReturnValue = IsBOINCCoreRunning();
- } else {
-
- // Get the full path to core client inside this application's bundle
- err = GetCurrentProcess (&ourPSN);
- if (err == noErr) {
- err = GetProcessBundleLocation(&ourPSN, &ourFSRef);
- }
- if (err == noErr) {
- err = FSRefMakePath (&ourFSRef, (UInt8*)buf, sizeof(buf));
- }
- if (err == noErr) {
-#if 0 // The Mac version of wxExecute(wxString& ...) crashes if there is a space in the path
- strExecute = wxT("\"");
- strExecute += wxT(buf);
- strExecute += wxT("/Contents/Resources/boinc\" --redirectio --launched_by_manager");
- m_lBOINCCoreProcessId = ::wxExecute(strExecute);
-#else // Use wxExecute(wxChar **argv ...) instead of wxExecute(wxString& ...)
- strcat(buf, "/Contents/Resources/boinc");
- argv[0] = buf;
- argv[1] = "--redirectio";
- argv[2] = "--launched_by_manager";
- argv[3] = NULL;
-#ifdef SANDBOX
- if (!g_use_sandbox) {
- argv[3] = "--insecure";
- argv[4] = NULL;
- }
-#endif
- // Under wxMac-2.8.0, wxExecute starts a separate thread
- // to wait for child's termination.
- // That wxProcessTerminationThread uses a huge amount of processor
- // time (about 11% of one CPU on 2GHz Intel Dual-Core Mac).
-// m_lBOINCCoreProcessId = ::wxExecute(argv);
- run_program(
- "/Library/Application Support/BOINC Data",
- buf, argv[3] ? 4 : 3, argv, 0.0, m_lBOINCCoreProcessId
- );
-#endif
- } else {
- buf[0] = '\0';
- }
- }
-
-#else // Unix based systems
-
- // Append boinc.exe to the end of the strExecute string and get ready to rock
- strExecute = ::wxGetCwd() + wxT("/boinc --redirectio --launched_by_manager");
-#ifdef SANDBOX
- if (!g_use_sandbox) {
- strExecute += wxT(" --insecure");
- }
-#endif
-
- wxLogTrace(wxT("Function Status"), wxT("CMainDocument::StartupBOINCCore - szExecute '%s'\n"), strExecute.c_str());
- wxLogTrace(wxT("Function Status"), wxT("CMainDocument::StartupBOINCCore - szDataDirectory '%s'\n"), ::wxGetCwd().c_str());
-
- m_lBOINCCoreProcessId = ::wxExecute(strExecute);
-
-#endif
-
- if (0 != m_lBOINCCoreProcessId) {
- m_bBOINCStartedByManager = true;
- bReturnValue = true;
- // Allow time for daemon to start up so we don't keep relaunching it
- for (int i=0; i<100; i++) { // Wait up to 1 seccond in 10 ms increments
- boinc_sleep(0.01);
- if (IsBOINCCoreRunning()) break;
- }
- }
-
- wxLogTrace(wxT("Function Start/End"), wxT("CMainDocument::StartupBOINCCore - Function End"));
- return bReturnValue;
-}
-
-
-#ifdef __WXMSW__
-
-//Adapted from http://www.codeproject.com/KB/threads/getprocessid.aspx
-/*****************************************************************
- * *
- * Functions used to navigate through the performance data. *
- * *
- *****************************************************************/
-
-PPERF_OBJECT_TYPE CBOINCClientManager::FirstObject( PPERF_DATA_BLOCK PerfData )
-{
- return( (PPERF_OBJECT_TYPE)((PBYTE)PerfData +
- PerfData->HeaderLength) );
-}
-
-PPERF_OBJECT_TYPE CBOINCClientManager::NextObject( PPERF_OBJECT_TYPE PerfObj )
-{
- return( (PPERF_OBJECT_TYPE)((PBYTE)PerfObj +
- PerfObj->TotalByteLength) );
-}
-
-PPERF_INSTANCE_DEFINITION CBOINCClientManager::FirstInstance( PPERF_OBJECT_TYPE PerfObj )
-{
- return( (PPERF_INSTANCE_DEFINITION)((PBYTE)PerfObj +
- PerfObj->DefinitionLength) );
-}
-
-PPERF_INSTANCE_DEFINITION CBOINCClientManager::NextInstance(
- PPERF_INSTANCE_DEFINITION PerfInst )
-{
- PPERF_COUNTER_BLOCK PerfCntrBlk;
-
- PerfCntrBlk = (PPERF_COUNTER_BLOCK)((PBYTE)PerfInst +
- PerfInst->ByteLength);
-
- return( (PPERF_INSTANCE_DEFINITION)((PBYTE)PerfCntrBlk +
- PerfCntrBlk->ByteLength) );
-}
-
-PPERF_COUNTER_DEFINITION CBOINCClientManager::FirstCounter( PPERF_OBJECT_TYPE PerfObj )
-{
- return( (PPERF_COUNTER_DEFINITION) ((PBYTE)PerfObj +
- PerfObj->HeaderLength) );
-}
-
-PPERF_COUNTER_DEFINITION CBOINCClientManager::NextCounter(
- PPERF_COUNTER_DEFINITION PerfCntr )
-{
- return( (PPERF_COUNTER_DEFINITION)((PBYTE)PerfCntr +
- PerfCntr->ByteLength) );
-}
-
-
-PPERF_COUNTER_BLOCK CBOINCClientManager::CounterBlock(PPERF_INSTANCE_DEFINITION PerfInst)
-{
- return (PPERF_COUNTER_BLOCK) ((LPBYTE) PerfInst + PerfInst->ByteLength);
-}
-
-#define TOTALBYTES 64*1024
-#define BYTEINCREMENT 1024
-
-#define PROCESS_OBJECT_INDEX 230
-#define PROC_ID_COUNTER 784
-
-
-DWORD CBOINCClientManager::GetProcessID(LPCTSTR pProcessName)
-{
- PPERF_DATA_BLOCK pPerfData = NULL;
- PPERF_OBJECT_TYPE pPerfObj;
- PPERF_INSTANCE_DEFINITION pPerfInst;
- PPERF_COUNTER_DEFINITION pPerfCntr, pCurCntr;
- PPERF_COUNTER_BLOCK PtrToCntr;
- DWORD BufferSize = TOTALBYTES;
- DWORD i, j;
- DWORD pdwValue;
- LONG k;
-
-// Allocate the buffer for the performance data.
- pPerfData = (PPERF_DATA_BLOCK) malloc( BufferSize );
-
-// char szKey[32];
-// sprintf(szKey,"%d %d",PROCESS_OBJECT_INDEX, PROC_ID_COUNTER);
- TCHAR szKey[32];
- _stprintf(szKey,TEXT("%d %d"),PROCESS_OBJECT_INDEX, PROC_ID_COUNTER);
- LONG lRes;
- while( (lRes = RegQueryValueEx( HKEY_PERFORMANCE_DATA,
- szKey,
- NULL,
- NULL,
- (LPBYTE) pPerfData,
- &BufferSize )) == ERROR_MORE_DATA )
- {
- // Get a buffer that is big enough.
- BufferSize += BYTEINCREMENT;
- pPerfData = (PPERF_DATA_BLOCK) realloc( pPerfData, BufferSize );
- }
-
- // Get the first object type.
- pPerfObj = FirstObject( pPerfData );
-
- // Process all objects.
- for( i=0; i < pPerfData->NumObjectTypes; i++ )
- {
-
- if (pPerfObj->ObjectNameTitleIndex != PROCESS_OBJECT_INDEX)
- {
- pPerfObj = NextObject( pPerfObj );
- continue;
- }
-
- // Get the first counter.
- pPerfCntr = FirstCounter( pPerfObj );
-
- // Get the first instance.
- pPerfInst = FirstInstance( pPerfObj );
-
- _bstr_t bstrProcessName,bstrInput;
-
- // Retrieve all instances.
- for( k=0; k < pPerfObj->NumInstances; k++ )
- {
- pCurCntr = pPerfCntr;
- bstrInput = pProcessName;
- bstrProcessName = (wchar_t *)((PBYTE)pPerfInst + pPerfInst->NameOffset);
- if (!_tcsicmp((LPCTSTR)bstrProcessName, (LPCTSTR) bstrInput))
- {
-
- // Retrieve all counters.
- for( j=0; j < pPerfObj->NumCounters; j++ )
- {
- if (pCurCntr->CounterNameTitleIndex == PROC_ID_COUNTER)
- {
- PtrToCntr = CounterBlock(pPerfInst);
- pdwValue = *((DWORD*)((LPBYTE) PtrToCntr + pCurCntr->CounterOffset));
- free(pPerfData);
- RegCloseKey(HKEY_PERFORMANCE_DATA);
- return pdwValue; }
-
- // Get the next counter.
- pCurCntr = NextCounter( pCurCntr );
- }
- }
-
- // Get the next instance.
- pPerfInst = NextInstance( pPerfInst );
- }
- }
- free(pPerfData);
- RegCloseKey(HKEY_PERFORMANCE_DATA);
-
- return 0;
-}
-
-bool CBOINCClientManager::ProcessExists(HANDLE *thePID) {
- DWORD dwExitCode = 0;
- DWORD processID = 0;
-
- if (*thePID == NULL) {
- processID = GetProcessID(TEXT("boinc"));
- if (processID != NULL) {
- // TODO: Can we get a handle to the process here for use by wxKill)?
- // *thePID = SOME_FUNCTION(processID);
- return true;
- }
- }
-
- if (*thePID != NULL) {
- if (GetExitCodeProcess(*thePID, &dwExitCode)) {
- if (STILL_ACTIVE == dwExitCode) {
- return true;
- }
- }
- }
-
- return false;
-}
-
-#else
-
-static char * PersistentFGets(char *buf, size_t buflen, FILE *f) {
- char *p = buf;
- size_t len = buflen;
- size_t datalen = 0;
-
- *buf = '\0';
- while (datalen < (buflen - 1)) {
- fgets(p, len, f);
- if (feof(f)) break;
- if (ferror(f) && (errno != EINTR)) break;
- if (strchr(buf, '\n')) break;
- datalen = strlen(buf);
- p = buf + datalen;
- len -= datalen;
- }
- return (buf[0] ? buf : NULL);
-}
-
-
-// On Mac, wxProcess::Exists returns true for zombies
-// because kill(pid, 0) returns OK for zombies
-// If we don;t have a pid, searches by name and returns pid if found.
-bool CBOINCClientManager::ProcessExists(pid_t* thePID) {
- FILE *f;
- char buf[1024];
- pid_t aPID;
- char name[] = "boinc";
- size_t n = strlen(name);
- char *bufp;
-
-
- if (*thePID) {
- sprintf(buf, "ps -a -x -c -o pid,state -p %d", *thePID);
- f = popen(buf, "r");
- if (f == NULL)
- return false;
-
- while (PersistentFGets(buf, sizeof(buf), f)) {
- aPID = atol(buf);
- if (aPID == *thePID) {
- if (strchr(buf, 'Z')) { // A 'zombie', stopped but waiting
- break; // for us (its parent) to quit
- }
- pclose(f);
- return true;
- }
- }
- pclose(f);
- return false;
- }
-
- f = popen("ps -a -x -c -o command,pid", "r");
- if (f == NULL)
- return 0;
-
- while (PersistentFGets(buf, sizeof(buf), f))
- {
- if (strncmp(buf, name, n) == 0)
- {
- bufp = buf+n-1;
- while (*++bufp == ' '); // Skip over white space
- *thePID = atol(bufp);
- pclose(f);
- return true;
- }
- }
- pclose(f);
- return false;
-}
-#endif
-
-
-#if defined(__WXMSW__)
-#define BOINCCoreProcessToTest m_hBOINCCoreProcess
-#else
-#define BOINCCoreProcessToTest m_lBOINCCoreProcessId
-#endif
-
-void CBOINCClientManager::ShutdownBOINCCore() {
- wxLogTrace(wxT("Function Start/End"), wxT("CBOINCClientManager::ShutdownBOINCCore - Function Begin"));
-
- CMainDocument* pDoc = wxGetApp().GetDocument();
- wxInt32 iCount = 0;
- bool bClientQuit = false;
- wxString strConnectedCompter = wxEmptyString;
- wxString strPassword = wxEmptyString;
-
- wxASSERT(pDoc);
- wxASSERT(wxDynamicCast(pDoc, CMainDocument));
-
- if (m_bBOINCStartedByManager) {
-#ifdef __WXMSW__
- if (IsBOINCConfiguredAsDaemon()) {
- StopBOINCService();
- bClientQuit = true;
- } else
-#endif
- {
- pDoc->GetConnectedComputerName(strConnectedCompter);
- if (!pDoc->IsComputerNameLocal(strConnectedCompter)) {
- RPC_CLIENT rpc;
- if (!rpc.init("localhost")) {
- pDoc->m_pNetworkConnection->GetLocalPassword(strPassword);
- rpc.authorize((const char*)strPassword.mb_str());
- if (ProcessExists(&BOINCCoreProcessToTest)) {
- rpc.quit();
- for (iCount = 0; iCount <= 10; iCount++) {
- if (!bClientQuit && ProcessExists(&BOINCCoreProcessToTest)) {
- wxLogTrace(wxT("Function Status"), wxT("CBOINCClientManager::ShutdownBOINCCore - (localhost) Application Exit Detected"));
- bClientQuit = true;
- break;
- }
- wxLogTrace(wxT("Function Status"), wxT("CBOINCClientManager::ShutdownBOINCCore - (localhost) Application Exit NOT Detected, Sleeping..."));
- ::wxSleep(1);
- }
- }
- }
- rpc.close();
- } else {
- if (ProcessExists(&BOINCCoreProcessToTest)) {
- pDoc->CoreClientQuit();
- for (iCount = 0; iCount <= 10; iCount++) {
- if (!bClientQuit && ProcessExists(&BOINCCoreProcessToTest)) {
- wxLogTrace(wxT("Function Status"), wxT("CBOINCClientManager::ShutdownBOINCCore - Application Exit Detected"));
- bClientQuit = true;
- break;
- }
- wxLogTrace(wxT("Function Status"), wxT("CBOINCClientManager::ShutdownBOINCCore - Application Exit NOT Detected, Sleeping..."));
- ::wxSleep(1);
- }
- }
- }
- }
-
- if (!bClientQuit) {
- ::wxKill(m_lBOINCCoreProcessId);
- }
- m_lBOINCCoreProcessId = 0;
- }
-
- wxLogTrace(wxT("Function Start/End"), wxT("CBOINCClientManager::ShutdownBOINCCore - Function End"));
-}
+// This file is part of BOINC.
+// http://boinc.berkeley.edu
+// Copyright (C) 2008 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 .
+
+#if defined(__GNUG__) && !defined(__APPLE__)
+#pragma implementation "BOINCClientManager.h"
+#endif
+
+#include "stdwx.h"
+#include "diagnostics.h"
+#include "LogBOINC.h"
+#include "BOINCGUIApp.h"
+#include "MainDocument.h"
+#include "BOINCBaseFrame.h"
+#include "AdvancedFrame.h"
+#include "BOINCClientManager.h"
+#include "error_numbers.h"
+
+#include "filesys.h"
+#include "util.h"
+
+#ifdef __WXMAC__
+enum {
+ NewStyleDaemon = 1,
+ OldStyleDaemon
+};
+#endif
+
+#ifdef __WXMSW__
+EXTERN_C BOOL IsBOINCServiceInstalled();
+EXTERN_C BOOL IsBOINCServiceStarting();
+EXTERN_C BOOL IsBOINCServiceRunning();
+EXTERN_C BOOL IsBOINCServiceStopping();
+EXTERN_C BOOL IsBOINCServiceStopped();
+EXTERN_C BOOL StartBOINCService();
+EXTERN_C BOOL StopBOINCService();
+#endif
+
+CBOINCClientManager::CBOINCClientManager() {
+ wxLogTrace(wxT("Function Start/End"), wxT("CBOINCClientManager::CBOINCClientManager - Function Begin"));
+
+ m_bBOINCStartedByManager = false;
+ m_lBOINCCoreProcessId = 0;
+
+#ifdef __WXMSW__
+ m_hBOINCCoreProcess = NULL;
+#endif
+
+ wxLogTrace(wxT("Function Start/End"), wxT("CBOINCClientManager::CBOINCClientManager - Function End"));
+}
+
+
+CBOINCClientManager::~CBOINCClientManager() {
+ wxLogTrace(wxT("Function Start/End"), wxT("CBOINCClientManager::~CBOINCClientManager - Function Begin"));
+
+ wxLogTrace(wxT("Function Start/End"), wxT("CBOINCClientManager::~CBOINCClientManager - Function End"));
+}
+
+
+bool CBOINCClientManager::AutoRestart() {
+ if (IsBOINCCoreRunning()) return true;
+#ifndef __WXMAC__ // Mac can restart Client as a daemon
+ if (! m_bBOINCStartedByManager) return false;
+#endif
+ m_lBOINCCoreProcessId = 0;
+ StartupBOINCCore();
+ return true;
+}
+
+
+bool CBOINCClientManager::IsSystemBooting() {
+ bool bReturnValue = false;
+#if defined(__WXMSW__)
+ if (GetTickCount() < (1000*60*5)) bReturnValue = true; // If system has been up for less than 5 minutes
+#elif defined(__WXMAC__)
+ if (TickCount() < (120*60)) bReturnValue = true; // If system has been up for less than 2 minutes
+#endif
+ return bReturnValue;
+}
+
+
+int CBOINCClientManager::IsBOINCConfiguredAsDaemon() {
+ bool bReturnValue = false;
+#if defined(__WXMSW__)
+ if (IsBOINCServiceInstalled()) bReturnValue = 1;
+#elif defined(__WXMAC__)
+ if ( boinc_file_exists("/Library/LaunchDaemons/edu.berkeley.boinc.plist")) {
+ bReturnValue = NewStyleDaemon; // New-style daemon uses launchd
+ }
+ if (boinc_file_exists("/Library/StartupItems/boinc/boinc") ) {
+ bReturnValue = OldStyleDaemon; // Old-style daemon uses StartupItem
+ }
+#endif
+ return bReturnValue;
+}
+
+
+bool CBOINCClientManager::IsBOINCCoreRunning() {
+ wxLogTrace(wxT("Function Start/End"), wxT("CBOINCClientManager::IsBOINCCoreRunning - Function Begin"));
+ bool running = false;
+
+#ifdef __WXMSW__
+ char buf[MAX_PATH] = "";
+
+ // Global mutex on Win2k and later
+ //
+ if (IsWindows2000Compatible()) {
+ strcpy(buf, "Global\\");
+ }
+ strcat( buf, RUN_MUTEX);
+
+ HANDLE h = CreateMutexA(NULL, true, buf);
+ if ((h==0) || (GetLastError() == ERROR_ALREADY_EXISTS)) {
+ running = true;
+ }
+#else
+ char path[1024];
+ static FILE_LOCK file_lock;
+
+ sprintf(path, "%s/%s", (char *)wxGetApp().GetDataDirectory().char_str(), LOCK_FILE_NAME);
+ if (file_lock.lock(path)) {
+ running = true;
+ } else {
+ file_lock.unlock(path);
+ }
+#endif
+ wxLogTrace(wxT("Function Status"), wxT("CBOINCClientManager::IsBOINCCoreRunning - Returning '%d'"), (int)running);
+ wxLogTrace(wxT("Function Start/End"), wxT("CBOINCClientManager::IsBOINCCoreRunning - Function End"));
+ return running;
+}
+
+
+bool CBOINCClientManager::StartupBOINCCore() {
+ wxLogTrace(wxT("Function Start/End"), wxT("CMainDocument::StartupBOINCCore - Function Begin"));
+
+ bool bReturnValue = false;
+ wxString strExecute = wxEmptyString;
+
+ if (IsBOINCCoreRunning()) return true;
+
+#if defined(__WXMSW__)
+ LPTSTR szExecute = NULL;
+ LPTSTR szDataDirectory = NULL;
+
+ if (IsBOINCConfiguredAsDaemon()) {
+ StartBOINCService();
+
+ m_bBOINCStartedByManager = true;
+ bReturnValue = IsBOINCCoreRunning();
+ } else {
+
+ // Append boinc.exe to the end of the strExecute string and get ready to rock
+ strExecute.Printf(
+ wxT("\"%s\\boinc.exe\" --redirectio --launched_by_manager %s"),
+ wxGetApp().GetRootDirectory().c_str(),
+ wxGetApp().GetArguments().c_str()
+ );
+
+ PROCESS_INFORMATION pi;
+ STARTUPINFO si;
+ BOOL bProcessStarted;
+
+ memset(&pi, 0, sizeof(pi));
+ memset(&si, 0, sizeof(si));
+
+ si.cb = sizeof(si);
+ si.dwFlags = STARTF_USESHOWWINDOW;
+ si.wShowWindow = SW_HIDE;
+
+ szExecute = (LPTSTR)strExecute.c_str();
+ if (wxGetApp().GetDataDirectory().empty()) {
+ szDataDirectory = NULL;
+ } else {
+ szDataDirectory = (LPTSTR)wxGetApp().GetDataDirectory().c_str();
+ }
+
+ wxLogTrace(wxT("Function Status"), wxT("CMainDocument::StartupBOINCCore - szExecute '%s'\n"), szExecute);
+ wxLogTrace(wxT("Function Status"), wxT("CMainDocument::StartupBOINCCore - szDataDirectory '%s'\n"), szDataDirectory);
+
+ bProcessStarted = CreateProcess(
+ NULL,
+ szExecute,
+ NULL,
+ NULL,
+ FALSE,
+ CREATE_NEW_PROCESS_GROUP|CREATE_NO_WINDOW,
+ NULL,
+ szDataDirectory,
+ &si,
+ &pi
+ );
+
+ if (bProcessStarted) {
+ m_lBOINCCoreProcessId = pi.dwProcessId;
+ m_hBOINCCoreProcess = pi.hProcess;
+ }
+ }
+
+#elif defined(__WXMAC__)
+
+#if 0 // The Mac version of wxExecute(wxString& ...) crashes if there is a space in the path
+ wxChar buf[1024];
+ wxChar *argv[5];
+#else
+ char buf[1024];
+ char *argv[5];
+#endif
+ ProcessSerialNumber ourPSN;
+ FSRef ourFSRef;
+ OSErr err;
+
+ if (IsBOINCConfiguredAsDaemon() == NewStyleDaemon) {
+ system ("launchctl load /Library/LaunchDaemons/edu.berkeley.boinc.plist");
+ system ("launchctl start edu.berkeley.boinc");
+ bReturnValue = IsBOINCCoreRunning();
+ } else {
+
+ // Get the full path to core client inside this application's bundle
+ err = GetCurrentProcess (&ourPSN);
+ if (err == noErr) {
+ err = GetProcessBundleLocation(&ourPSN, &ourFSRef);
+ }
+ if (err == noErr) {
+ err = FSRefMakePath (&ourFSRef, (UInt8*)buf, sizeof(buf));
+ }
+ if (err == noErr) {
+#if 0 // The Mac version of wxExecute(wxString& ...) crashes if there is a space in the path
+ strExecute = wxT("\"");
+ strExecute += wxT(buf);
+ strExecute += wxT("/Contents/Resources/boinc\" --redirectio --launched_by_manager");
+ m_lBOINCCoreProcessId = ::wxExecute(strExecute);
+#else // Use wxExecute(wxChar **argv ...) instead of wxExecute(wxString& ...)
+ strcat(buf, "/Contents/Resources/boinc");
+ argv[0] = buf;
+ argv[1] = "--redirectio";
+ argv[2] = "--launched_by_manager";
+ argv[3] = NULL;
+#ifdef SANDBOX
+ if (!g_use_sandbox) {
+ argv[3] = "--insecure";
+ argv[4] = NULL;
+ }
+#endif
+ // Under wxMac-2.8.0, wxExecute starts a separate thread
+ // to wait for child's termination.
+ // That wxProcessTerminationThread uses a huge amount of processor
+ // time (about 11% of one CPU on 2GHz Intel Dual-Core Mac).
+// m_lBOINCCoreProcessId = ::wxExecute(argv);
+ run_program(
+ "/Library/Application Support/BOINC Data",
+ buf, argv[3] ? 4 : 3, argv, 0.0, m_lBOINCCoreProcessId
+ );
+#endif
+ } else {
+ buf[0] = '\0';
+ }
+ }
+
+#else // Unix based systems
+
+ // Append boinc.exe to the end of the strExecute string and get ready to rock
+ strExecute = ::wxGetCwd() + wxT("/boinc --redirectio --launched_by_manager");
+#ifdef SANDBOX
+ if (!g_use_sandbox) {
+ strExecute += wxT(" --insecure");
+ }
+#endif
+
+ wxLogTrace(wxT("Function Status"), wxT("CMainDocument::StartupBOINCCore - szExecute '%s'\n"), strExecute.c_str());
+ wxLogTrace(wxT("Function Status"), wxT("CMainDocument::StartupBOINCCore - szDataDirectory '%s'\n"), ::wxGetCwd().c_str());
+
+ m_lBOINCCoreProcessId = ::wxExecute(strExecute);
+
+#endif
+
+ if (0 != m_lBOINCCoreProcessId) {
+ m_bBOINCStartedByManager = true;
+ bReturnValue = true;
+ // Allow time for daemon to start up so we don't keep relaunching it
+ for (int i=0; i<100; i++) { // Wait up to 1 seccond in 10 ms increments
+ boinc_sleep(0.01);
+ if (IsBOINCCoreRunning()) break;
+ }
+ }
+
+ wxLogTrace(wxT("Function Start/End"), wxT("CMainDocument::StartupBOINCCore - Function End"));
+ return bReturnValue;
+}
+
+
+#ifdef __WXMSW__
+void CBOINCClientManager::KillClient(HANDLE processHandle) {
+ unsigned int i,j;
+ std::vector ps;
+
+ if (processHandle != NULL) {
+ ::wxKill(processHandle);
+ return;
+ }
+
+ // Get a list of currently executing processes.
+ diagnostics_update_process_list(ps);
+
+ // Find our root process that we are supposed to terminate and
+ // terminate it.
+ for (i=0; i < ps.size(); i++) {
+ BOINC_PROCESS& p = ps[i];
+ if (downcase_string(p.strProcessName) == downcase_string(strProcessName)) {
+ TerminateProcessById(p.dwProcessId));
+ }
+ }
+ }
+}
+
+#else
+
+static char * PersistentFGets(char *buf, size_t buflen, FILE *f) {
+ char *p = buf;
+ size_t len = buflen;
+ size_t datalen = 0;
+
+ *buf = '\0';
+ while (datalen < (buflen - 1)) {
+ fgets(p, len, f);
+ if (feof(f)) break;
+ if (ferror(f) && (errno != EINTR)) break;
+ if (strchr(buf, '\n')) break;
+ datalen = strlen(buf);
+ p = buf + datalen;
+ len -= datalen;
+ }
+ return (buf[0] ? buf : NULL);
+}
+
+
+// On Mac, wxProcess::Exists returns true for zombies
+// because kill(pid, 0) returns OK for zombies
+// If we don't have a pid, searches by name.
+void CBOINCClientManager::KillClient(pid_t thePID) {
+ FILE *f;
+ char buf[1024];
+ char name[] = "boinc";
+ size_t n = strlen(name);
+ char *bufp;
+ pid_t apPID;
+
+ if (thePID) {
+ kill_program(thePID);
+ return;
+ }
+
+ f = popen("ps -a -x -c -o command,pid", "r");
+ if (f == NULL)
+ return;
+
+ while (PersistentFGets(buf, sizeof(buf), f))
+ {
+ if (strncmp(buf, name, n) == 0)
+ {
+ bufp = buf+n-1;
+ while (*++bufp == ' '); // Skip over white space
+ apPID = atol(bufp);
+ kill_program(apPID);
+ break;
+ }
+ }
+ pclose(f);
+}
+#endif
+
+
+void CBOINCClientManager::ShutdownBOINCCore() {
+ wxLogTrace(wxT("Function Start/End"), wxT("CBOINCClientManager::ShutdownBOINCCore - Function Begin"));
+
+ CMainDocument* pDoc = wxGetApp().GetDocument();
+ wxInt32 iCount = 0;
+ bool bClientQuit = false;
+ wxString strConnectedCompter = wxEmptyString;
+ wxString strPassword = wxEmptyString;
+
+ wxASSERT(pDoc);
+ wxASSERT(wxDynamicCast(pDoc, CMainDocument));
+
+ if (m_bBOINCStartedByManager) {
+#ifdef __WXMSW__
+ if (IsBOINCConfiguredAsDaemon()) {
+ StopBOINCService();
+ bClientQuit = true;
+ } else
+#endif
+ {
+ pDoc->GetConnectedComputerName(strConnectedCompter);
+ if (!pDoc->IsComputerNameLocal(strConnectedCompter)) {
+ RPC_CLIENT rpc;
+ if (!rpc.init("localhost")) {
+ pDoc->m_pNetworkConnection->GetLocalPassword(strPassword);
+ rpc.authorize((const char*)strPassword.mb_str());
+ if (IsBOINCCoreRunning()) {
+ rpc.quit();
+ for (iCount = 0; iCount <= 10; iCount++) {
+ if (!bClientQuit && !IsBOINCCoreRunning()) {
+ wxLogTrace(wxT("Function Status"), wxT("CBOINCClientManager::ShutdownBOINCCore - (localhost) Application Exit Detected"));
+ bClientQuit = true;
+ break;
+ }
+ wxLogTrace(wxT("Function Status"), wxT("CBOINCClientManager::ShutdownBOINCCore - (localhost) Application Exit NOT Detected, Sleeping..."));
+ ::wxSleep(1);
+ }
+ }
+ }
+ rpc.close();
+ } else {
+ if (IsBOINCCoreRunning()) {
+ pDoc->CoreClientQuit();
+ for (iCount = 0; iCount <= 10; iCount++) {
+ if (!bClientQuit && !IsBOINCCoreRunning()) {
+ wxLogTrace(wxT("Function Status"), wxT("CBOINCClientManager::ShutdownBOINCCore - Application Exit Detected"));
+ bClientQuit = true;
+ break;
+ }
+ wxLogTrace(wxT("Function Status"), wxT("CBOINCClientManager::ShutdownBOINCCore - Application Exit NOT Detected, Sleeping..."));
+ ::wxSleep(1);
+ }
+ }
+ }
+ }
+
+ if (!bClientQuit) {
+ KillClient(m_lBOINCCoreProcessId);
+ }
+ m_lBOINCCoreProcessId = 0;
+ }
+
+ wxLogTrace(wxT("Function Start/End"), wxT("CBOINCClientManager::ShutdownBOINCCore - Function End"));
+}
diff --git a/clientgui/BOINCClientManager.h b/clientgui/BOINCClientManager.h
index d5e228526f..081289da4d 100644
--- a/clientgui/BOINCClientManager.h
+++ b/clientgui/BOINCClientManager.h
@@ -1,71 +1,60 @@
-// This file is part of BOINC.
-// http://boinc.berkeley.edu
-// Copyright (C) 2008 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 .
-
-#ifndef _BOINCCLIENTMANAGER_H_
-#define _BOINCCLIENTMANAGER_H_
-
-#if defined(__GNUG__) && !defined(__APPLE__)
-#pragma interface "BOINCClientManager.cpp"
-#endif
-
-class CBOINCClientManager : public wxObject
-{
-public:
-
- CBOINCClientManager();
- ~CBOINCClientManager();
-
- bool AutoRestart();
-
- bool IsSystemBooting();
- int IsBOINCConfiguredAsDaemon();
-
- void DisableBOINCStartedByManager() { m_bBOINCStartedByManager = false; };
- void EnableBOINCStartedByManager() { m_bBOINCStartedByManager = true; };
- bool WasBOINCStartedByManager() { return m_bBOINCStartedByManager; };
-
- bool IsBOINCCoreRunning();
- bool StartupBOINCCore();
- void ShutdownBOINCCore();
-
-protected:
-
- bool m_bBOINCStartedByManager;
- int m_lBOINCCoreProcessId;
-
-#ifdef __WXMSW__
- PPERF_OBJECT_TYPE FirstObject( PPERF_DATA_BLOCK PerfData );
- PPERF_OBJECT_TYPE NextObject( PPERF_OBJECT_TYPE PerfObj );
- PPERF_INSTANCE_DEFINITION FirstInstance( PPERF_OBJECT_TYPE PerfObj );
- PPERF_INSTANCE_DEFINITION NextInstance( PPERF_INSTANCE_DEFINITION PerfInst );
- PPERF_COUNTER_DEFINITION FirstCounter( PPERF_OBJECT_TYPE PerfObj );
- PPERF_COUNTER_DEFINITION NextCounter( PPERF_COUNTER_DEFINITION PerfCntr );
- PPERF_COUNTER_BLOCK CounterBlock(PPERF_INSTANCE_DEFINITION PerfInst);
- DWORD GetProcessID(LPCTSTR pProcessName);
-
- bool ProcessExists(HANDLE* thePID);
- HANDLE m_hBOINCCoreProcess;
-#else
- bool ProcessExists(pid_t* thePID);
-
-#endif
-
-};
-
-
-#endif
-
+// This file is part of BOINC.
+// http://boinc.berkeley.edu
+// Copyright (C) 2008 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 .
+
+#ifndef _BOINCCLIENTMANAGER_H_
+#define _BOINCCLIENTMANAGER_H_
+
+#if defined(__GNUG__) && !defined(__APPLE__)
+#pragma interface "BOINCClientManager.cpp"
+#endif
+
+class CBOINCClientManager : public wxObject
+{
+public:
+
+ CBOINCClientManager();
+ ~CBOINCClientManager();
+
+ bool AutoRestart();
+
+ bool IsSystemBooting();
+ int IsBOINCConfiguredAsDaemon();
+
+ void DisableBOINCStartedByManager() { m_bBOINCStartedByManager = false; };
+ void EnableBOINCStartedByManager() { m_bBOINCStartedByManager = true; };
+ bool WasBOINCStartedByManager() { return m_bBOINCStartedByManager; };
+
+ bool IsBOINCCoreRunning();
+ bool StartupBOINCCore();
+ void ShutdownBOINCCore();
+
+protected:
+ bool m_bBOINCStartedByManager;
+ int m_lBOINCCoreProcessId;
+
+#ifdef __WXMSW__
+ void KillClient(HANDLE processHandle);
+ HANDLE m_hBOINCCoreProcess;
+#else
+ void KillClient(pid_t thePID);
+#endif
+
+};
+
+
+#endif
+