mirror of https://github.com/BOINC/boinc.git
Patches from Reinhard Prix to fix several problems.
(1) apps being suspended would call boinc_finish(nonzero) and core client would treat this as app failure. Introduce a new function boinc_exit() and call that instead. (2) improvements to GUI build with wxWidgets (3) improved X event handling loop now ensures that X window is taken away when window killed. svn path=/trunk/boinc/; revision=5142
This commit is contained in:
parent
240c121a00
commit
37a49c9b09
|
@ -72,7 +72,6 @@ static double time_until_fraction_done_update;
|
|||
static double fraction_done;
|
||||
static double last_checkpoint_cpu_time;
|
||||
static bool ready_to_checkpoint = false;
|
||||
static bool time_to_quit = false;
|
||||
static double last_wu_cpu_time;
|
||||
static bool standalone = false;
|
||||
static double initial_wu_cpu_time;
|
||||
|
@ -138,7 +137,7 @@ int boinc_init_options_general(BOINC_OPTIONS& opt) {
|
|||
}
|
||||
if (retval) {
|
||||
fprintf(stderr, "Can't acquire lockfile - exiting\n");
|
||||
boinc_finish(0); // not un-recoverable ==> status=0
|
||||
boinc_exit(0); // not un-recoverable ==> status=0
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -162,7 +161,7 @@ int boinc_init_options_general(BOINC_OPTIONS& opt) {
|
|||
fprintf(stderr, "Core client has wrong major version: wanted %d, got %d\n",
|
||||
BOINC_MAJOR_VERSION, aid.core_version/100
|
||||
);
|
||||
boinc_finish(ERR_MAJOR_VERSION); // un-recoverable==> exit with nonzero status
|
||||
boinc_exit(ERR_MAJOR_VERSION); // un-recoverable==> exit with nonzero status
|
||||
}
|
||||
retval = setup_shared_mem();
|
||||
if (retval) {
|
||||
|
@ -205,14 +204,10 @@ static void send_trickle_up_msg() {
|
|||
|
||||
|
||||
// NOTE: a non-zero status tells a running client that we're exiting with
|
||||
// and "unrecoverable error", which will be reported back to server.
|
||||
// Therefore, on "recoverable errors", use exit-status == 0 !
|
||||
// an "unrecoverable error", which will be reported back to server.
|
||||
// A zero exit-status will tell the client we've successfully finished the result.
|
||||
int boinc_finish(int status) {
|
||||
|
||||
// remove the lockfile
|
||||
if ( boinc_delete_file (LOCKFILE) != 0)
|
||||
perror ("boinc_finish(): failed to remove lockfile");
|
||||
|
||||
if (options.send_status_msgs) {
|
||||
boinc_calling_thread_cpu_time(last_checkpoint_cpu_time);
|
||||
last_checkpoint_cpu_time += aid.wu_cpu_time;
|
||||
|
@ -235,27 +230,45 @@ int boinc_finish(int status) {
|
|||
boinc_write_init_data_file();
|
||||
}
|
||||
|
||||
// now remove lockfile+exit
|
||||
boinc_exit(status);
|
||||
|
||||
return(0); // doh... we never get here
|
||||
} // boinc_finish()
|
||||
|
||||
|
||||
// exit a boinc-app
|
||||
// this simply closes, then removes the app's lockfile and
|
||||
// calls the appropriate exit-function
|
||||
#if (!defined _WIN32) && (!defined HANDLE)
|
||||
typedef int HANDLE;
|
||||
#endif
|
||||
extern HANDLE app_lockfile_handle;
|
||||
|
||||
void
|
||||
boinc_exit (int status)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
exit(status);
|
||||
if ( !CloseHandle ( app_lockfile_handle ) )
|
||||
perror ( "Failed to close the application-lockfile.");
|
||||
#else
|
||||
// on Linux < 2.6, probably due to non-POSIX LinuxThreads, _Exit() fails to
|
||||
// shut down the graphics-thread properly, while exit() does the job and does _NOT_
|
||||
// seem to get tangled in exit-atexit loops...
|
||||
#ifdef __linux__
|
||||
exit(status);
|
||||
#else
|
||||
// on Mac (and supposedly other systems with POSIX-complian thread-implementations?),
|
||||
// calling exit() can lead to infinite exit-atexit loops, while _Exit() seems to behave nicely
|
||||
// This is not pretty but unless someone finds a cleaner solution, we handle the two cases
|
||||
// separately based on these observations
|
||||
_Exit(status);
|
||||
if ( close ( app_lockfile_handle ) )
|
||||
perror ( "Failed to close the application-lockfile " LOCKFILE);
|
||||
#endif
|
||||
// remove the lockfile
|
||||
if ( boinc_delete_file (LOCKFILE) != 0)
|
||||
perror ("boinc_finish(): failed to remove lockfile");
|
||||
|
||||
// on Mac, calling exit() can lead to infinite exit-atexit loops, while _exit() seems
|
||||
// to behave nicely. This is not pretty but unless someone finds a cleaner solution,
|
||||
// we handle the Mac-case separately .
|
||||
#ifdef __APPLE_CC__
|
||||
_exit(status);
|
||||
#else
|
||||
exit(status);
|
||||
#endif
|
||||
|
||||
fprintf(stderr, "..exit() or _Exit() returned... this is totally weird!!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // boinc_exit()
|
||||
|
||||
bool boinc_is_standalone() {
|
||||
return standalone;
|
||||
|
@ -427,7 +440,7 @@ static void handle_process_control_msg() {
|
|||
break;
|
||||
}
|
||||
if (match_tag(buf, "<quit/>")) {
|
||||
boinc_finish(0); // NOTE: exit-status = 0 !
|
||||
boinc_exit(0); // NOTE: exit-status = 0 ==> recoverable exit!
|
||||
}
|
||||
}
|
||||
boinc_sleep(1.0);
|
||||
|
@ -449,7 +462,7 @@ static void handle_process_control_msg() {
|
|||
if (match_tag(buf, "<quit/>")) {
|
||||
boinc_status.quit_request = true;
|
||||
if (options.direct_process_action) {
|
||||
boinc_finish(0); // NOTE: exit-status == 0!
|
||||
boinc_exit(0); // NOTE: exit-status == 0!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -494,9 +507,9 @@ static void worker_timer(int a) {
|
|||
now - (heartbeat_giveup_time - HEARTBEAT_GIVEUP_PERIOD)
|
||||
);
|
||||
if (options.direct_process_action) {
|
||||
boinc_finish(0); // NOTE: exit-status == 0! (recoverable error)
|
||||
boinc_exit(0); // NOTE: exit-status == 0! (recoverable error)
|
||||
} else {
|
||||
boinc_status.no_heartbeat = true;
|
||||
boinc_status.no_heartbeat = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -602,8 +615,8 @@ int boinc_time_to_checkpoint() {
|
|||
|
||||
// If the application has received a quit request it should checkpoint
|
||||
//
|
||||
if (time_to_quit || ready_to_checkpoint) {
|
||||
return 1;
|
||||
if (ready_to_checkpoint) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -618,12 +631,6 @@ int boinc_checkpoint_completed() {
|
|||
ready_to_checkpoint = false;
|
||||
time_until_checkpoint = aid.checkpoint_period;
|
||||
|
||||
// If it's time to quit, call boinc_finish which will exit the app properly
|
||||
//
|
||||
if (time_to_quit) {
|
||||
fprintf(stderr, "Received quit request from core client\n");
|
||||
boinc_finish(ERR_QUIT_REQUEST);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -65,6 +65,7 @@ struct BOINC_STATUS {
|
|||
|
||||
extern int boinc_init(void);
|
||||
extern int boinc_finish(int status);
|
||||
extern void boinc_exit (int status);
|
||||
extern int boinc_resolve_filename(const char*, char*, int len);
|
||||
extern int boinc_parse_init_data_file(void);
|
||||
extern int boinc_write_init_data_file(void);
|
||||
|
|
|
@ -36,6 +36,15 @@ static APP_INIT_DATA aid;
|
|||
extern pthread_t graphics_thread; // thread info
|
||||
extern pthread_t worker_thread;
|
||||
|
||||
enum
|
||||
{
|
||||
JUMP_NONE = 0,
|
||||
JUMP_EXIT,
|
||||
JUMP_ABORT,
|
||||
JUMP_LAST
|
||||
}; // possible longjmp-values to signal from where we jumped:
|
||||
// 1= exit caught by atexit, 2 = signal caught by handler
|
||||
|
||||
|
||||
void app_debug_msg (char *fmt, ...);
|
||||
|
||||
|
@ -155,15 +164,19 @@ void KillWindow() {
|
|||
|
||||
void set_mode(int mode) {
|
||||
if (mode == current_graphics_mode) return;
|
||||
|
||||
app_debug_msg("set_mode(%d): current_mode = %d. Calling KillWindow(): win = %d\n", mode, current_graphics_mode, win);
|
||||
KillWindow();
|
||||
app_debug_msg("...KillWindow() survived.\n");
|
||||
current_graphics_mode = mode;
|
||||
|
||||
if (mode != MODE_HIDE_GRAPHICS) {
|
||||
app_debug_msg("set_mode(): Calling make_new_window(%d)\n", mode);
|
||||
make_new_window(mode);
|
||||
app_debug_msg("...make_new_window() survived.\n");
|
||||
}
|
||||
|
||||
current_graphics_mode = mode;
|
||||
|
||||
return;
|
||||
} // set_mode()
|
||||
|
||||
|
@ -231,10 +244,10 @@ void restart()
|
|||
{
|
||||
app_debug_msg ("exit() called from graphics-thread.\n");
|
||||
|
||||
// we're standalone, a glut-window was open: user must have pressed 'close', so we exit
|
||||
if (boinc_is_standalone() && glut_is_initialized && win)
|
||||
// if we are standalone and glut was initialized, we assume user pressed 'close', and we exit the app
|
||||
if ( boinc_is_standalone() && glut_is_initialized )
|
||||
{
|
||||
app_debug_msg("Open glut-window found... means we're exiting now.\n");
|
||||
app_debug_msg("Assuming user pressed 'close'... means we're exiting now.\n");
|
||||
if ( boinc_delete_file(LOCKFILE) != 0)
|
||||
perror ("Failed to remove lockfile..\n");
|
||||
return;
|
||||
|
@ -244,7 +257,7 @@ void restart()
|
|||
atexit(restart);
|
||||
// jump back to entry-point in xwin_graphics_event_loop();
|
||||
app_debug_msg( "Jumping back to event_loop.\n");
|
||||
longjmp(jbuf, 1);
|
||||
longjmp(jbuf, JUMP_EXIT);
|
||||
} // if in graphics-thread
|
||||
|
||||
return;
|
||||
|
@ -262,7 +275,7 @@ void restart_sig(int signal_number)
|
|||
fprintf(stderr, "Caught SIGABRT in graphics thread\n");
|
||||
app_debug_msg ("Caught SIGABRT in graphics thread. Jumping back to xwin_graphics_event_loop()...\n");
|
||||
// jump back to entry-point in xwin_graphics_event_loop()
|
||||
longjmp(jbuf, 1);
|
||||
longjmp(jbuf, JUMP_ABORT);
|
||||
} // if ABRT raised in graphics-thread
|
||||
else
|
||||
{
|
||||
|
@ -295,7 +308,7 @@ void restart_sig(int signal_number)
|
|||
// NOTE: this should only be called *ONCE* by an application
|
||||
void xwin_graphics_event_loop()
|
||||
{
|
||||
int restarted;
|
||||
int restarted = 0;
|
||||
|
||||
app_debug_msg ("Direct call to xwin_graphics_event_loop()\n");
|
||||
|
||||
|
@ -317,54 +330,46 @@ void xwin_graphics_event_loop()
|
|||
// THIS IS THE re-entry point at exit or ABORT in the graphics-thread
|
||||
restarted = setjmp(jbuf);
|
||||
|
||||
if (restarted)
|
||||
app_debug_msg("xwin_graphics_event_loop() restarted at re-entry point\n");
|
||||
|
||||
// if we came here from an ABORT-signal thrown in this thread, we put this thread to sleep
|
||||
if ( restarted == JUMP_ABORT )
|
||||
while(1)
|
||||
sleep(1);
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// running in standalone-mode:
|
||||
if ( boinc_is_standalone() )
|
||||
{
|
||||
if (restarted && !win) // now window was yet opened: just go to sleep to avoid more trouble...
|
||||
{
|
||||
app_debug_msg("Graphics exited before glut-window opened... continuing without graphics\n");
|
||||
while(1) sleep(1);
|
||||
return; // should never arrive here
|
||||
} // if restarted & no open windows
|
||||
|
||||
if ( !restarted ) // first time through here
|
||||
if (restarted)
|
||||
while(1) sleep(1); // assuming glutInit() failed: put graphics-thread to sleep
|
||||
else
|
||||
{
|
||||
// open the graphics-window
|
||||
set_mode(MODE_WINDOW);
|
||||
glutTimerFunc(TIMER_INTERVAL_MSEC, timer_handler, 0);
|
||||
glutTimerFunc(TIMER_INTERVAL_MSEC, timer_handler, 0);
|
||||
}
|
||||
} // if standalone-mode
|
||||
else // under BOINC: start with graphics hidden and wait for client to tell us otherwise
|
||||
} // if boinc_is_standalone
|
||||
//----------------------------------------------------------------------
|
||||
// runing under BOINC-client:
|
||||
else
|
||||
{
|
||||
if ( !glut_is_initialized )
|
||||
{
|
||||
set_mode(MODE_HIDE_GRAPHICS);
|
||||
while ( current_graphics_mode == MODE_HIDE_GRAPHICS )
|
||||
{
|
||||
app_debug_msg ("Graphics-thread now waiting for client-message...\n");
|
||||
wait_for_initial_message();
|
||||
app_debug_msg ("got a graphics-message from client... \n");
|
||||
timer_handler(0);
|
||||
} // while MODE_HIDE_GRAPHICS
|
||||
} // glut_is_initialized = false
|
||||
else
|
||||
// here glut has been initialized previously
|
||||
// probably the user pressed window-'close'
|
||||
set_mode(MODE_HIDE_GRAPHICS); // close any previously open windows
|
||||
}// if running under BOINC
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
// Mac's GLUT is sufficiently "broken" that I simply don't see a way of restarting
|
||||
// a GLUT-window after user exited once (e.g. using M-Q, or "Quit einstein" in menu).
|
||||
// glut will segfault or similar at the attempt, so we rather don't try this in the first place.
|
||||
// ==> If user exited glut-window once on mac, we put this thread to sleep
|
||||
// (until somebody has a better idea / understanding of Mac's glut
|
||||
#ifdef __APPLE_CC__
|
||||
if (restarted)
|
||||
{
|
||||
app_debug_msg("Sorry. I don't know a way of restarting glut on the Mac. Putting graphics to sleep now.\n");
|
||||
while(1) sleep(1);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
// on Linux on the other hand, glut seems to be happily restartable after exit was caught,
|
||||
// so we simply continue as if it was the first time...: i.e. wait for client-message, then do something.
|
||||
app_debug_msg ("Switching graphics-mode to MODE_HIDE_GRAPHICS\n");
|
||||
set_mode(MODE_HIDE_GRAPHICS);
|
||||
while ( current_graphics_mode == MODE_HIDE_GRAPHICS )
|
||||
{
|
||||
app_debug_msg ("Graphics-thread now waiting for client-message...\n");
|
||||
wait_for_initial_message();
|
||||
app_debug_msg ("got a graphics-message from client... \n");
|
||||
timer_handler(0);
|
||||
}
|
||||
} // ! boinc_is_standalone()
|
||||
|
||||
// ok we should be ready & initialized by now to call glutMainLoop()
|
||||
app_debug_msg ("now calling glutMainLoop()...\n");
|
||||
glutMainLoop();
|
||||
|
|
|
@ -22937,3 +22937,23 @@ David 18 Jan 2005
|
|||
am_confirm.php
|
||||
am_create.php
|
||||
am_query.php
|
||||
|
||||
Bruce 19 Jan 2005
|
||||
- Patches from Reinhard Prix to fix several problems.
|
||||
(1) apps being suspended would call boinc_finish(nonzero) and
|
||||
core client would treat this as app failure. Introduce
|
||||
a new function boinc_exit() and call that instead.
|
||||
(2) improvements to GUI build with wxWidgets
|
||||
(3) improved X event handling loop now ensures that X window
|
||||
is taken away when window killed.
|
||||
configure.ac
|
||||
clientgui/
|
||||
Makefile.am
|
||||
api/
|
||||
boinc_api.h
|
||||
boinc_api.C
|
||||
x_opengl.C
|
||||
lib/
|
||||
filesys.C
|
||||
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ EXTRA_DIST = BOINCBaseView.h DlgAttachProject.h ValidateAccountKey.h ViewWork
|
|||
|
||||
boinc_gui_CPPFLAGS = $(AM_CPPFLAGS) $(WX_CPPFLAGS) $(CLIENTGUIFLAGS)
|
||||
boinc_gui_CXXFLAGS = $(AM_CXXFLAGS) $(WX_CXXFLAGS) $(CLIENTGUIFLAGS)
|
||||
boinc_gui_LDADD = $(PTHREAD_LIBS) $(WX_LIBS) $(CLIENTGUILIBS)
|
||||
boinc_gui_LDADD = $(PTHREAD_LIBS) $(WX_LIBS)
|
||||
|
||||
all-local: client_gui-bin
|
||||
client_gui-bin: @CLIENT_GUI_BIN_FILENAME@
|
||||
|
|
22
configure.ac
22
configure.ac
|
@ -307,24 +307,14 @@ WARNING: wxWidgets could not be found ==> building client without clientgui.
|
|||
fi
|
||||
|
||||
AM_CONDITIONAL(BUILD_CLIENTGUI, [ test "$wxWin" = 1 -a "${enable_client}" = yes ])
|
||||
|
||||
if ( test "${enable_client}" = yes ) && ( test "$wxWin" = 1 ); then
|
||||
CLIENTGUIFLAGS="-DNOCLIPBOARD -DNOTASKBAR"
|
||||
AC_SUBST(CLIENTGUIFLAGS)
|
||||
fi
|
||||
|
||||
dnl --------------------------------------------------------------------------------
|
||||
|
||||
|
||||
dnl This is one way to set up host-specific stuff
|
||||
case "${host}" in
|
||||
*-*-linux* | *-*-solaris* )
|
||||
dnl no taskbar support in wxWidgets
|
||||
CLIENTGUIFLAGS="-DNOCLIPBOARD -DNOTASKBAR";
|
||||
AC_SUBST(CLIENTGUIFLAGS)
|
||||
AC_SUBST(CLIENTGUILIBS) ;;
|
||||
*-*-darwin*)
|
||||
dnl no taskbar support in wxWidgets
|
||||
CLIENTGUIFLAGS="-DNOCLIPBOARD -DNOTASKBAR";
|
||||
CLIENTGUILIBS="-framework QuickTime -framework IOKit -framework Carbon -framework Cocoa -framework System -licon -framework WebKit";
|
||||
AC_SUBST(CLIENTGUIFLAGS)
|
||||
AC_SUBST(CLIENTGUILIBS) ;;
|
||||
esac
|
||||
|
||||
dnl Here's another way to set up host-specific stuff
|
||||
AM_CONDITIONAL(OS_DARWIN, [echo $host_os | grep '^darwin' > /dev/null])
|
||||
AM_CONDITIONAL(OS_LINUX, [echo $host_os | grep '^linux' > /dev/null])
|
||||
|
|
|
@ -463,40 +463,50 @@ int boinc_make_dirs(const char* dirpath, const char* filepath) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// provide some file-locking mechanism to ensure only one app is running
|
||||
// in a slot
|
||||
|
||||
#if (!defined _WIN32) && (!defined HANDLE)
|
||||
typedef int HANDLE;
|
||||
#endif
|
||||
HANDLE app_lockfile_handle;
|
||||
|
||||
int lock_file(char* filename) {
|
||||
int retval;
|
||||
|
||||
#ifdef _WIN32
|
||||
HANDLE hfile = CreateFile(
|
||||
app_lockfile_handle = CreateFile(
|
||||
filename, GENERIC_WRITE,
|
||||
0, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0
|
||||
);
|
||||
if (hfile == INVALID_HANDLE_VALUE) retval = 1;
|
||||
else
|
||||
// NOTE: contrary to unix, we close the file on windows, so that we can remove it later in boinc_finish().
|
||||
// there seems to be no real file-locking done here, so this should be ok...
|
||||
if (CloseHandle(hfile))
|
||||
retval = 0;
|
||||
else
|
||||
retval = 1;
|
||||
|
||||
// some systems have both!
|
||||
);
|
||||
if (app_lockfile_handle == INVALID_HANDLE_VALUE)
|
||||
retval = 1;
|
||||
// some systems have both!
|
||||
#elif defined(HAVE_LOCKF) && !defined(__APPLE__)
|
||||
int fd = open(filename, O_WRONLY|O_CREAT, 0644);
|
||||
retval = lockf(fd, F_TLOCK, 0);
|
||||
app_lockfile_handle = open(filename, O_WRONLY|O_CREAT, 0644);
|
||||
retval = lockf(app_lockfile_handle, F_TLOCK, 0);
|
||||
#elif HAVE_FLOCK
|
||||
app_lockfile_handle = open(filename, O_WRONLY|O_CREAT, 0644);
|
||||
retval = flock(app_lockfile_handle, LOCK_EX|LOCK_NB);
|
||||
// must leave file-handle open
|
||||
#else
|
||||
no file lock mechanism;
|
||||
#endif
|
||||
|
||||
#ifndef NDEBUG
|
||||
if ( retval != 0 )
|
||||
{
|
||||
struct flock lck;
|
||||
fprintf(stdout, "DEBUG: Failed to get lockf on %s. Error = %d, %s\n", filename, errno, strerror(errno));
|
||||
perror ("DEBUG: Failed to get lock on application-lockfile");
|
||||
lck.l_whence = 0;
|
||||
lck.l_start = 0L;
|
||||
lck.l_len = 0L;
|
||||
lck.l_type = F_WRLCK;
|
||||
(void) fcntl(fd, F_GETLK, &lck);
|
||||
(void) fcntl(app_lockfile_handle, F_GETLK, &lck);
|
||||
if (lck.l_type != F_UNLCK)
|
||||
fprintf(stdout, "DEBUG: Lock-info: pid = %d type = %c start = %8ld len = %8ld\n", lck.l_pid,
|
||||
(lck.l_type == F_WRLCK) ? 'W' : 'R', lck.l_start, lck.l_len);
|
||||
(lck.l_type == F_WRLCK) ? 'W' : 'R', lck.l_start, lck.l_len);
|
||||
else
|
||||
fprintf(stdout, "DEBUG: fcntl() says it's unlocked though....strange.\n");
|
||||
|
||||
|
@ -504,14 +514,6 @@ int lock_file(char* filename) {
|
|||
}
|
||||
#endif // defined NDEBUG
|
||||
|
||||
#elif HAVE_FLOCK
|
||||
int fd = open(filename, O_WRONLY|O_CREAT, 0644);
|
||||
retval = flock(fd, LOCK_EX|LOCK_NB);
|
||||
// must leave fd open
|
||||
#else
|
||||
no file lock mechanism;
|
||||
#endif
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue