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;
}