From 5dc3068df8bf6ddf579d72dbba6d4533499bd530 Mon Sep 17 00:00:00 2001 From: Charlie Fenton Date: Sat, 6 Jun 2009 00:26:44 +0000 Subject: [PATCH] MGR: Use code like get_client_mutex() to determine if client is running; KillClient() uses process name if we don't have pid. svn path=/trunk/boinc/; revision=18316 --- checkin_notes | 9 + clientgui/BOINCClientManager.cpp | 1060 +++++++++++++----------------- clientgui/BOINCClientManager.h | 131 ++-- 3 files changed, 517 insertions(+), 683 deletions(-) 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 +