mirror of https://github.com/BOINC/boinc.git
screensaver: Implement new screensaver coordinator logic as requested by Rom.
svn path=/trunk/boinc/; revision=17322
This commit is contained in:
parent
72e5c0fc0d
commit
b4c78c27b4
|
@ -1290,7 +1290,7 @@ Charlie Feb 5 2009
|
|||
clientscr/
|
||||
screensaver.cpp
|
||||
mac_saver_module.cpp
|
||||
Mac_Saver_Module.cpp.h
|
||||
Mac_Saver_Module.h
|
||||
screensaver_win.h
|
||||
ss_app.cpp
|
||||
mac_build/
|
||||
|
@ -1745,3 +1745,24 @@ Charlie 19 Feb 2009
|
|||
|
||||
clientscr/
|
||||
ss_app.cpp
|
||||
|
||||
Charlie 20 Feb 2009
|
||||
- screensaver: Implement new screensaver coordinator logic as requested by Rom:
|
||||
If the coordinator cannot connect to the core client:
|
||||
- coordinator retries connecting every 10 seconds
|
||||
- coordinator launches the default graphics application with the
|
||||
argument --retry_connect, so the default graphics app will continue
|
||||
running and will also retry connecting every 10 seconds.
|
||||
If the coordinator successfully connected to the core client, it launches the
|
||||
default graphics application without the argument --retry_connect. If the
|
||||
default graphics application can't connect, it will return immediately
|
||||
with the exit code ERR_CONNECT. In that case, the coordinator assumes
|
||||
the default graphics app was blocked by a firewall and so the coordinator
|
||||
will run only project (science) graphics.
|
||||
|
||||
clientscr/
|
||||
mac_saver_module.cpp
|
||||
Mac_Saver_Module.h
|
||||
ss_app.cpp
|
||||
screensaver.cpp,.h
|
||||
screensaver_win.cpp,.h
|
||||
|
|
|
@ -91,6 +91,7 @@ protected:
|
|||
double m_fGFXChangePeriod;
|
||||
bool m_bScience_gfx_running;
|
||||
bool m_bDefault_gfx_running;
|
||||
bool m_bConnected;
|
||||
|
||||
//
|
||||
// Data management layer
|
||||
|
@ -107,6 +108,7 @@ protected:
|
|||
void HandleRPCError(void);
|
||||
OSErr KillScreenSaver(void);
|
||||
void GetDisplayPeriods(char *dir_path);
|
||||
bool HasProcessExited(pid_t pid, int &exitCode);
|
||||
pthread_t m_hDataManagementThread;
|
||||
pid_t m_hGraphicsApplication;
|
||||
|
||||
|
@ -116,7 +118,7 @@ protected:
|
|||
// Count the number of active graphics-capable apps
|
||||
int count_active_graphic_apps(RESULTS& results, RESULT* exclude = NULL);
|
||||
|
||||
// Choose a ramdom graphics application from the vector that
|
||||
// Choose a random graphics application from the vector that
|
||||
// was passed in.
|
||||
|
||||
RESULT* get_random_graphics_app(RESULTS& results, RESULT* exclude = NULL);
|
||||
|
|
|
@ -83,6 +83,7 @@ static long gSystemVersion = 0;
|
|||
const char * CantLaunchCCMsg = "Unable to launch BOINC application.";
|
||||
const char * LaunchingCCMsg = "Launching BOINC application.";
|
||||
const char * ConnectingCCMsg = "Connecting to BOINC application.";
|
||||
const char * ConnectedCCMsg = "Communicating with BOINC application.";
|
||||
const char * BOINCSuspendedMsg = "BOINC is currently suspended.";
|
||||
const char * BOINCNoAppsExecutingMsg = "BOINC is currently idle.";
|
||||
const char * BOINCNoProjectsDetectedMsg = "BOINC is not attached to any projects. Please attach to projects using the BOINC Manager.";
|
||||
|
@ -174,6 +175,7 @@ CScreensaver::CScreensaver() {
|
|||
m_hGraphicsApplication = NULL;
|
||||
m_bResetCoreState = TRUE;
|
||||
rpc = 0;
|
||||
m_bConnected = false;
|
||||
|
||||
err = Gestalt(gestaltSystemVersion, &gSystemVersion);
|
||||
if (err != noErr) {
|
||||
|
@ -262,7 +264,7 @@ OSStatus CScreensaver::initBOINCApp() {
|
|||
|
||||
m_CoreClientPID = FindProcessPID("boinc", 0);
|
||||
if (m_CoreClientPID) {
|
||||
m_wasAlreadyRunning = true;
|
||||
m_wasAlreadyRunning = true;
|
||||
saverState = SaverState_LaunchingCoreClient;
|
||||
return noErr;
|
||||
}
|
||||
|
@ -344,11 +346,14 @@ int CScreensaver::getSSMessage(char **theMessage, int* coveredFreq) {
|
|||
setSSMessageText(LaunchingCCMsg);
|
||||
|
||||
myPid = FindProcessPID(NULL, m_CoreClientPID);
|
||||
if (myPid) {
|
||||
if (myPid) {
|
||||
saverState = SaverState_CoreClientRunning;
|
||||
rpc->init(NULL); // Initialize communications with Core Client
|
||||
if (!rpc->init(NULL)) { // Initialize communications with Core Client
|
||||
m_bConnected = true;
|
||||
}
|
||||
|
||||
// Set up a separate thread for communicating with Core Client
|
||||
// Set up a separate thread for communicating with Core Client
|
||||
// and running screensaver graphics
|
||||
CreateDataManagementThread();
|
||||
// ToDo: Add a timeout after which we display error message
|
||||
} else
|
||||
|
@ -371,6 +376,7 @@ int CScreensaver::getSSMessage(char **theMessage, int* coveredFreq) {
|
|||
case SaverState_ConnectedToCoreClient:
|
||||
switch (m_hrError) {
|
||||
case 0:
|
||||
setSSMessageText(ConnectedCCMsg);
|
||||
break; // No status response yet from DataManagementProc
|
||||
case SCRAPPERR_SCREENSAVERBLANKED:
|
||||
default:
|
||||
|
@ -447,6 +453,9 @@ int CScreensaver::getSSMessage(char **theMessage, int* coveredFreq) {
|
|||
|
||||
case SaverState_CantLaunchCoreClient:
|
||||
setSSMessageText(CantLaunchCCMsg);
|
||||
// Set up a separate thread for running screensaver graphics
|
||||
// even if we can't communicate with core client
|
||||
CreateDataManagementThread();
|
||||
break;
|
||||
|
||||
case SaverState_Idle:
|
||||
|
@ -507,19 +516,32 @@ void * CScreensaver::DataManagementProcStub(void* param) {
|
|||
|
||||
|
||||
void CScreensaver::HandleRPCError() {
|
||||
static time_t last_RPC_retry = 0;
|
||||
|
||||
// Attempt to restart BOINC Client if needed, reinitialize the RPC client and state
|
||||
rpc->close();
|
||||
m_bConnected = false;
|
||||
|
||||
// There is a possible race condition where the Core Client was in the
|
||||
// process of shutting down just as ScreenSaver started, so initBOINCApp()
|
||||
// found it already running but now it has shut down. This code takes
|
||||
// care of that and other situations where the Core Client quits unexpectedy.
|
||||
if (FindProcessPID("boinc", 0) == 0) {
|
||||
saverState = SaverState_RelaunchCoreClient;
|
||||
m_bResetCoreState = true;
|
||||
}
|
||||
|
||||
rpc->init(NULL); // Otherwise just reinitialize the RPC client and state and keep trying
|
||||
if (saverState == SaverState_CantLaunchCoreClient) {
|
||||
if ((time(0) - last_RPC_retry) < RPC_RETRY_INTERVAL) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// There is a possible race condition where the Core Client was in the
|
||||
// process of shutting down just as ScreenSaver started, so initBOINCApp()
|
||||
// found it already running but now it has shut down. This code takes
|
||||
// care of that and other situations where the Core Client quits unexpectedy.
|
||||
// Code in initBOINC_App() limits # launch retries to 3 to prevent thrashing.
|
||||
if (FindProcessPID("boinc", 0) == 0) {
|
||||
saverState = SaverState_RelaunchCoreClient;
|
||||
m_bResetCoreState = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise just reinitialize the RPC client and state and keep trying
|
||||
if (!rpc->init(NULL)) {
|
||||
m_bConnected = true;
|
||||
}
|
||||
// Error message after timeout?
|
||||
}
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include "util.h"
|
||||
#include "common_defs.h"
|
||||
#include "filesys.h"
|
||||
#include "error_numbers.h"
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
|
@ -45,11 +46,13 @@
|
|||
#define PATH_SEPARATOR (_T("\\"))
|
||||
#define THE_DEFAULT_SS_EXECUTABLE (_T(DEFAULT_SS_EXECUTABLE))
|
||||
#define THE_SS_CONFIG_FILE (_T(SS_CONFIG_FILE))
|
||||
#define DEFAULT_GFX_CANT_CONNECT ERR_CONNECT
|
||||
#else
|
||||
// Using (_T()) here causes compiler errors on Mac
|
||||
#define PATH_SEPARATOR "/"
|
||||
#define THE_DEFAULT_SS_EXECUTABLE DEFAULT_SS_EXECUTABLE
|
||||
#define THE_SS_CONFIG_FILE SS_CONFIG_FILE
|
||||
#define DEFAULT_GFX_CANT_CONNECT (ERR_CONNECT & 0xff)
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
@ -324,6 +327,7 @@ int CScreensaver::launch_default_screensaver(char *dir_path, int& graphics_appli
|
|||
{
|
||||
int retval = 0;
|
||||
char full_path[1024];
|
||||
int num_args = 2;
|
||||
|
||||
strlcpy(full_path, dir_path, sizeof(full_path));
|
||||
strlcat(full_path, PATH_SEPARATOR, sizeof(full_path));
|
||||
|
@ -333,14 +337,20 @@ int CScreensaver::launch_default_screensaver(char *dir_path, int& graphics_appli
|
|||
// "RegisterProcess failed (error = -50)" unless we pass its
|
||||
// full path twice in the argument list to execv on Macs.
|
||||
|
||||
char* argv[3];
|
||||
char* argv[4];
|
||||
argv[0] = full_path; // not used
|
||||
argv[1] = "--fullscreen";
|
||||
argv[2] = 0;
|
||||
argv[3] = 0;
|
||||
if (!m_bConnected) {
|
||||
BOINCTRACE(_T("launch_default_screensaver using --retry_connect argument\n"));
|
||||
argv[2] = "--retry_connect";
|
||||
num_args = 3;
|
||||
}
|
||||
retval = run_program(
|
||||
dir_path,
|
||||
full_path,
|
||||
2,
|
||||
num_args,
|
||||
argv,
|
||||
0,
|
||||
graphics_application
|
||||
|
@ -351,6 +361,16 @@ int CScreensaver::launch_default_screensaver(char *dir_path, int& graphics_appli
|
|||
}
|
||||
|
||||
|
||||
// If we cannot connect to the core client:
|
||||
// - we retry connecting every 10 seconds
|
||||
// - we launch the default graphics application with the argument --retry_connect, so
|
||||
// it will continue running and will also retry connecting every 10 seconds.
|
||||
//
|
||||
// If we successfully connected to the core client, launch the default graphics application
|
||||
// without the argument --retry_connect. If it can't connect, it will return immediately
|
||||
// with the exit code ERR_CONNECT. In that case, we assume it was blocked by a firewall
|
||||
// and so we run only project (science) graphics.
|
||||
|
||||
#ifdef _WIN32
|
||||
DWORD WINAPI CScreensaver::DataManagementProc()
|
||||
#else
|
||||
|
@ -376,6 +396,7 @@ void *CScreensaver::DataManagementProc()
|
|||
|
||||
SS_PHASE ss_phase = DEFAULT_SS_PHASE;
|
||||
bool switch_to_default_gfx = false;
|
||||
int exit_status = 0;
|
||||
|
||||
char* default_ss_dir_path = NULL;
|
||||
char* default_data_dir_path = NULL;
|
||||
|
@ -480,32 +501,39 @@ retval = 0;
|
|||
m_QuitDataManagementProc = true;
|
||||
}
|
||||
|
||||
// Do we need to get the core client state?
|
||||
if (m_bResetCoreState) {
|
||||
// Try and get the current state of the CC
|
||||
retval = rpc->get_state(state);
|
||||
if (retval) {
|
||||
// CC may not yet be running
|
||||
HandleRPCError();
|
||||
continue;
|
||||
}
|
||||
|
||||
m_bResetCoreState = false;
|
||||
}
|
||||
|
||||
BOINCTRACE(_T("CScreensaver::DataManagementProc - ErrorMode = '%d', ErrorCode = '%x'\n"), m_bErrorMode, m_hrError);
|
||||
|
||||
// Update our task list
|
||||
m_updating_results = true;
|
||||
retval = rpc->get_screensaver_tasks(suspend_reason, results);
|
||||
m_updating_results = false;
|
||||
if (retval) {
|
||||
// rpc call returned error
|
||||
if (! m_bConnected) {
|
||||
HandleRPCError();
|
||||
m_bResetCoreState = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (m_bConnected) {
|
||||
// Do we need to get the core client state?
|
||||
if (m_bResetCoreState) {
|
||||
// Try and get the current state of the CC
|
||||
retval = rpc->get_state(state);
|
||||
if (retval) {
|
||||
// CC may not yet be running
|
||||
HandleRPCError();
|
||||
} else {
|
||||
m_bResetCoreState = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Update our task list
|
||||
m_updating_results = true;
|
||||
retval = rpc->get_screensaver_tasks(suspend_reason, results);
|
||||
m_updating_results = false;
|
||||
if (retval) {
|
||||
// rpc call returned error
|
||||
HandleRPCError();
|
||||
m_bResetCoreState = true;
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
results.clear();
|
||||
}
|
||||
|
||||
// Time to switch to default graphics phase?
|
||||
if (m_bDefault_ss_exists && (ss_phase == SCIENCE_SS_PHASE)) {
|
||||
if (science_phase_start_time && ((dtime() - science_phase_start_time) > m_fGFxSciencePeriod)) {
|
||||
|
@ -524,7 +552,7 @@ retval = 0;
|
|||
}
|
||||
|
||||
// Time to switch to science graphics phase?
|
||||
if (ss_phase == DEFAULT_SS_PHASE) {
|
||||
if ((ss_phase == DEFAULT_SS_PHASE) && m_bConnected) {
|
||||
if (default_phase_start_time &&
|
||||
((dtime() - default_phase_start_time + default_saver_duration_in_science_phase)
|
||||
> m_fGFXDefaultPeriod)) {
|
||||
|
@ -739,10 +767,18 @@ retval = 0;
|
|||
|
||||
// Is the graphics app still running?
|
||||
if (m_hGraphicsApplication) {
|
||||
if (!process_exists(m_hGraphicsApplication)) {
|
||||
if (HasProcessExited(m_hGraphicsApplication, exit_status)) {
|
||||
// Something has happened to the previously selected screensaver
|
||||
// application. Start a different one.
|
||||
BOINCTRACE(_T("CScreensaver::DataManagementProc - Graphics application isn't running, start a new one.\n"));
|
||||
if (m_bDefault_gfx_running) {
|
||||
// If we were able to connect to core client but gfx app can't, don't use it.
|
||||
BOINCTRACE(_T("CScreensaver::DataManagementProc - Default graphics application exited with code %d.\n"), exit_status);
|
||||
if (exit_status == DEFAULT_GFX_CANT_CONNECT) {
|
||||
m_bDefault_ss_exists = false;
|
||||
ss_phase = SCIENCE_SS_PHASE;
|
||||
}
|
||||
}
|
||||
m_hGraphicsApplication = 0;
|
||||
graphics_app_result_ptr = NULL;
|
||||
m_bDefault_gfx_running = false;
|
||||
|
@ -759,6 +795,33 @@ retval = 0;
|
|||
}
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
BOOL CScreensaver::HasProcessExited(HANDLE pid_handle, int &exitCode) {
|
||||
unsigned long status = 1;
|
||||
if (GetExitCodeProcess(pid_handle, &status)) {
|
||||
if (status == STILL_ACTIVE) {
|
||||
exitCode = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
exitCode = (int)status;
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
bool CScreensaver::HasProcessExited(pid_t pid, int &exitCode) {
|
||||
int status;
|
||||
pid_t p;
|
||||
|
||||
p = waitpid(pid, &status, WNOHANG);
|
||||
exitCode = WEXITSTATUS(status);
|
||||
if (p == pid) return true; // process has exited
|
||||
if (p == -1) return true; // PID doesn't exist
|
||||
exitCode = 0;
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void CScreensaver::GetDisplayPeriods(char *dir_path) {
|
||||
char buf[1024];
|
||||
FILE* f;
|
||||
|
|
|
@ -29,6 +29,8 @@ enum SS_PHASE {
|
|||
SCIENCE_SS_PHASE
|
||||
};
|
||||
|
||||
#define RPC_RETRY_INTERVAL 10 /* # of seconds between retries connecting to core client */
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Error / status codes
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
|
@ -184,6 +184,7 @@ CScreensaver::CScreensaver() {
|
|||
m_dwBlankTime = 0;
|
||||
|
||||
rpc = NULL;
|
||||
m_bConnected = false;
|
||||
m_hDataManagementThread = NULL;
|
||||
m_hGraphicsApplication = NULL;
|
||||
m_bResetCoreState = TRUE;
|
||||
|
@ -954,6 +955,8 @@ BOOL CScreensaver::CreateDataManagementThread() {
|
|||
BOINCTRACE(_T("CScreensaver::CreateDataManagementThread: Failed to create data management thread '%d'\n"), GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
m_tThreadCreateTime = time(0);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -995,12 +998,26 @@ DWORD WINAPI CScreensaver::DataManagementProcStub(LPVOID UNUSED(lpParam)) {
|
|||
|
||||
void CScreensaver::HandleRPCError()
|
||||
{
|
||||
// Attempt to reinitialize the RPC client and state
|
||||
rpc->close();
|
||||
rpc->init(NULL);
|
||||
m_bResetCoreState = TRUE;
|
||||
static time_t last_RPC_retry = 0;
|
||||
time_t now = time(0);
|
||||
|
||||
if ((time(0) - m_tThreadCreateTime) > 3) {
|
||||
rpc->close();
|
||||
m_bConnected = false;
|
||||
|
||||
if ((now - m_tThreadCreateTime) > 3) {
|
||||
if ((now - last_RPC_retry) < RPC_RETRY_INTERVAL) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Attempt to reinitialize the RPC client and state
|
||||
if (!rpc->init(NULL)) {
|
||||
m_bConnected = true;
|
||||
m_bResetCoreState = TRUE;
|
||||
return;
|
||||
}
|
||||
|
||||
if ((now - m_tThreadCreateTime) > 3) {
|
||||
SetError(TRUE, SCRAPPERR_BOINCNOTDETECTED);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -144,7 +144,6 @@ protected:
|
|||
DWORD m_dwBlankScreen;
|
||||
DWORD m_dwBlankTime;
|
||||
|
||||
|
||||
//
|
||||
// Data management layer
|
||||
//
|
||||
|
@ -164,6 +163,7 @@ protected:
|
|||
int launch_default_screensaver(char *dir_path, HANDLE& graphics_application);
|
||||
void HandleRPCError(void);
|
||||
void GetDisplayPeriods(char *dir_path);
|
||||
BOOL HasProcessExited(HANDLE pid_handle, int &exitCode);
|
||||
|
||||
// Determine if two RESULT pointers refer to the same task
|
||||
bool is_same_task(RESULT* taska, RESULT* taskb);
|
||||
|
@ -197,6 +197,7 @@ protected:
|
|||
|
||||
bool m_bScience_gfx_running;
|
||||
bool m_bDefault_gfx_running;
|
||||
BOOL m_bConnected;
|
||||
|
||||
//
|
||||
// Presentation layer
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#include "gui_rpc_client.h"
|
||||
#include "util.h"
|
||||
#include "app_ipc.h"
|
||||
#include "error_numbers.h"
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
@ -365,7 +366,7 @@ void app_graphics_render(int xs, int ys, double t) {
|
|||
}
|
||||
if (retval) {
|
||||
if (!retry_connect) {
|
||||
exit(retval);
|
||||
exit(ERR_CONNECT);
|
||||
}
|
||||
next_connect_time = t + 10;
|
||||
} else {
|
||||
|
@ -390,7 +391,7 @@ void app_graphics_render(int xs, int ys, double t) {
|
|||
retval = update_data();
|
||||
if (retval) {
|
||||
if (!retry_connect) {
|
||||
exit(retval);
|
||||
exit(ERR_CONNECT);
|
||||
}
|
||||
connected = false;
|
||||
next_connect_time = t + 10;
|
||||
|
@ -446,10 +447,10 @@ int main(int argc, char** argv) {
|
|||
bool test = false;
|
||||
|
||||
for (int i=1; i<argc; i++) {
|
||||
if (!strcmp(argv[1], "--test")) {
|
||||
if (!strcmp(argv[i], "--test")) {
|
||||
test = true;
|
||||
}
|
||||
if (!strcmp(argv[1], "--retry_connect")) {
|
||||
if (!strcmp(argv[i], "--retry_connect")) {
|
||||
retry_connect = true;
|
||||
}
|
||||
}
|
||||
|
@ -462,7 +463,7 @@ int main(int argc, char** argv) {
|
|||
if (!retval) {
|
||||
retval = update_data();
|
||||
}
|
||||
exit(retval);
|
||||
exit(ERR_CONNECT);
|
||||
}
|
||||
|
||||
boinc_graphics_loop(argc, argv);
|
||||
|
|
Loading…
Reference in New Issue