From c3425dbb6cb10880cba5e54f0a70117c0f753a64 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 3 Feb 2006 20:48:48 +0000 Subject: [PATCH] let apps handle abort requests svn path=/trunk/boinc/; revision=9400 --- api/boinc_api.C | 16 ++++++++++++---- api/boinc_api.h | 3 ++- checkin_notes | 27 +++++++++++++++++++++++++++ client/app.C | 13 ++++++++++--- client/app.h | 3 +++ client/app_control.C | 26 ++++++++++++++++++++------ 6 files changed, 74 insertions(+), 14 deletions(-) diff --git a/api/boinc_api.C b/api/boinc_api.C index 90e0d2a46a..aa3b564920 100644 --- a/api/boinc_api.C +++ b/api/boinc_api.C @@ -262,6 +262,7 @@ int boinc_init_options_general(BOINC_OPTIONS& opt) { boinc_status.no_heartbeat = false; boinc_status.suspended = false; boinc_status.quit_request = false; + boinc_status.abort_request = false; if (options.main_program) { // make sure we're the only app running in this slot @@ -309,10 +310,11 @@ int boinc_init_options_general(BOINC_OPTIONS& opt) { return 0; } -int boinc_get_status(BOINC_STATUS& s) { - s.no_heartbeat = boinc_status.no_heartbeat; - s.suspended = boinc_status.suspended; - s.quit_request = boinc_status.quit_request; +int boinc_get_status(BOINC_STATUS *s) { + s->no_heartbeat = boinc_status.no_heartbeat; + s->suspended = boinc_status.suspended; + s->quit_request = boinc_status.quit_request; + s->abort_request = boinc_status.abort_request; return 0; } @@ -576,6 +578,12 @@ static void handle_process_control_msg() { boinc_exit(0); } } + if (match_tag(buf, "")) { + boinc_status.abort_request = true; + if (options.direct_process_action) { + boinc_exit(0); + } + } if (match_tag(buf, "")) { boinc_status.reread_init_data_file = true; } diff --git a/api/boinc_api.h b/api/boinc_api.h index 8d5df89693..24c0827a13 100755 --- a/api/boinc_api.h +++ b/api/boinc_api.h @@ -56,6 +56,7 @@ struct BOINC_STATUS { int suspended; int quit_request; int reread_init_data_file; + int abort_request; }; extern int boinc_init(void); @@ -98,7 +99,7 @@ extern int setMacIcon(char *filename, char *iconData, long iconSize); #include "app_ipc.h" extern int boinc_init_options(BOINC_OPTIONS&); -extern int boinc_get_status(BOINC_STATUS&); +extern int boinc_get_status(BOINC_STATUS*); extern int boinc_resolve_filename_s(const char*, std::string&); extern int boinc_get_init_data(APP_INIT_DATA&); extern int boinc_wu_cpu_time(double&); diff --git a/checkin_notes b/checkin_notes index 1f77cd30c2..115cbc5324 100755 --- a/checkin_notes +++ b/checkin_notes @@ -1444,3 +1444,30 @@ David 2 Feb 2005 client/ cs_apps.C + +David 3 Feb 2005 + - Allow apps to do cleanup when they're aborted. + - Add abort_request to BOINC_STATUS structure + - API library: handle message + - Change boinc_get_status() arg from reference + to pointer (for easier FORTRAN interface). + This is an API change, but I think only CPDN uses this. + - ACTIVE_TASK_SET::poll(): + Check for processes that are ABORT_PENDING + for more than 5 seconds, and kill them + + From Carl Christensen, somewhat modified. + I changed the way tasks are aborted. + The core client can't sleep; that locks up the UI. + So we can't sleep 5 seconds waiting for an app to exit + after sending it an message + (existing apps don't recognize this message). + Instead, send it the message, + set its state to PROCESS_ABORT_PENDING, + and check it from the polling loop 5 seconds later. + + api/ + boinc_api.C,h + client/ + app.C,h + app_control.C diff --git a/client/app.C b/client/app.C index 52fd726033..7179f8ff10 100644 --- a/client/app.C +++ b/client/app.C @@ -194,7 +194,7 @@ void ACTIVE_TASK_SET::free_mem() { } #endif -// Do period checks on running apps: +// Do periodic checks on running apps: // - get latest CPU time and % done info // - check if any has exited, and clean up // - see if any has exceeded its CPU or disk space limits, and abort it @@ -211,9 +211,16 @@ bool ACTIVE_TASK_SET::poll() { graphics_poll(); process_control_poll(); action |= check_rsc_limits_exceeded(); - if (get_msgs()) { - action = true; + action |= get_msgs(); + for (unsigned int i=0; itask_state == PROCESS_ABORT_PENDING) { + if (gstate.now > atp->abort_time + 5.0) { + atp->kill_task(); + } + } } + if (action) { gstate.set_client_state_dirty("ACTIVE_TASK_SET::poll"); } diff --git a/client/app.h b/client/app.h index 6b73d90a4a..b27fe5e943 100644 --- a/client/app.h +++ b/client/app.h @@ -126,6 +126,8 @@ public: int want_network; // This task wants to do network comm (for F@h) // this is passed via share-memory message (app_status channel) + double abort_time; // when we sent an abort message to this app + // kill it 5 seconds later if it doesn't exit APP_CLIENT_SHM app_client_shm; // core/app shared mem MSG_QUEUE graphics_request_queue; @@ -154,6 +156,7 @@ public: int request_exit(); // ask the process to exit gracefully, // i.e. by sending a message + int request_abort(); // send "abort" message bool process_exists(); int kill_task(); // Kill process forcibly, diff --git a/client/app_control.C b/client/app_control.C index 984332c3c4..d3982b05cc 100644 --- a/client/app_control.C +++ b/client/app_control.C @@ -77,14 +77,24 @@ bool ACTIVE_TASK::process_exists() { int ACTIVE_TASK::request_exit() { if (!app_client_shm.shm) return 1; process_control_queue.msg_queue_send( - "", + "", app_client_shm.shm->process_control_request ); return 0; } -// send a kill signal. -// This is not caught by the process +// Send an abort message. +// +int ACTIVE_TASK::request_abort() { + if (!app_client_shm.shm) return 1; + process_control_queue.msg_queue_send( + "", + app_client_shm.shm->process_control_request + ); + return 0; +} + +// Kill the task by OS-specific means. // int ACTIVE_TASK::kill_task() { #ifdef _WIN32 @@ -529,13 +539,17 @@ bool ACTIVE_TASK_SET::check_rsc_limits_exceeded() { return did_anything; } -// If process is running, send it a kill signal -// This is done when app has exceeded CPU, disk, or mem limits +// If process is running, send it an "abort" message, +// and if it doesn't exit within 5 seconds, +// kill it by OS-specific mechanism (e.g. KILL signal). +// This is done when app has exceeded CPU, disk, or mem limits, +// or when the user has requested it. // int ACTIVE_TASK::abort_task(int exit_status, const char* msg) { if (task_state == PROCESS_EXECUTING || task_state == PROCESS_SUSPENDED) { task_state = PROCESS_ABORT_PENDING; - kill_task(); + abort_time = gstate.now; + request_abort(); } else { task_state = PROCESS_ABORTED; }