2005-01-20 23:22:22 +00:00
|
|
|
// Berkeley Open Infrastructure for Network Computing
|
|
|
|
// http://boinc.berkeley.edu
|
|
|
|
// Copyright (C) 2005 University of California
|
2004-08-11 11:30:25 +00:00
|
|
|
//
|
2005-01-20 23:22:22 +00:00
|
|
|
// This 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 2.1 of the License, or (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This software 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.
|
|
|
|
//
|
|
|
|
// To view the GNU Lesser General Public License visit
|
|
|
|
// http://www.gnu.org/copyleft/lesser.html
|
|
|
|
// or write to the Free Software Foundation, Inc.,
|
|
|
|
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
2004-08-11 11:30:25 +00:00
|
|
|
|
|
|
|
// monitoring and process control of running apps
|
|
|
|
|
|
|
|
#include "cpp.h"
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
#include "boinc_win.h"
|
|
|
|
#else
|
2005-11-21 18:34:44 +00:00
|
|
|
#include "config.h"
|
2004-08-11 11:30:25 +00:00
|
|
|
|
2005-11-21 18:34:44 +00:00
|
|
|
#ifdef HAVE_UNISTD_H
|
2004-08-11 11:30:25 +00:00
|
|
|
#include <unistd.h>
|
2005-11-21 18:34:44 +00:00
|
|
|
#endif
|
2004-08-11 11:30:25 +00:00
|
|
|
|
|
|
|
#if HAVE_SYS_IPC_H
|
|
|
|
#include <sys/ipc.h>
|
|
|
|
#endif
|
2004-08-11 15:27:46 +00:00
|
|
|
#if HAVE_SYS_RESOURCE_H
|
|
|
|
#include <sys/resource.h>
|
|
|
|
#endif
|
2005-11-21 18:34:44 +00:00
|
|
|
#ifdef HAVE_CSIGNAL
|
|
|
|
#include <csignal>
|
|
|
|
#elif defined(HAVE_SYS_SIGNAL_H)
|
2004-08-11 11:30:25 +00:00
|
|
|
#include <sys/signal.h>
|
2005-11-21 18:34:44 +00:00
|
|
|
#elif defined(HAVE_SIGNAL_H)
|
|
|
|
#include <signal.h>
|
2004-08-11 11:30:25 +00:00
|
|
|
#endif
|
2004-08-11 15:27:46 +00:00
|
|
|
#if HAVE_SYS_WAIT_H
|
|
|
|
#include <sys/wait.h>
|
|
|
|
#endif
|
2004-08-11 11:30:25 +00:00
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
using std::vector;
|
|
|
|
|
|
|
|
#include "filesys.h"
|
|
|
|
#include "error_numbers.h"
|
|
|
|
#include "util.h"
|
|
|
|
#include "parse.h"
|
|
|
|
#include "shmem.h"
|
|
|
|
#include "client_msgs.h"
|
|
|
|
#include "client_state.h"
|
|
|
|
#include "file_names.h"
|
|
|
|
|
|
|
|
#include "app.h"
|
|
|
|
|
2004-08-23 22:06:48 +00:00
|
|
|
bool ACTIVE_TASK::process_exists() {
|
2005-01-21 23:26:36 +00:00
|
|
|
switch (task_state) {
|
|
|
|
case PROCESS_EXECUTING:
|
|
|
|
case PROCESS_SUSPENDED:
|
|
|
|
case PROCESS_ABORT_PENDING:
|
|
|
|
return true;
|
|
|
|
}
|
2004-08-23 22:06:48 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Send a quit message.
|
2004-08-11 11:30:25 +00:00
|
|
|
//
|
|
|
|
int ACTIVE_TASK::request_exit() {
|
2004-08-24 21:44:54 +00:00
|
|
|
if (!app_client_shm.shm) return 1;
|
2004-09-13 05:27:28 +00:00
|
|
|
process_control_queue.msg_queue_send(
|
2006-02-03 20:48:48 +00:00
|
|
|
"<quit/>",
|
2004-09-13 05:27:28 +00:00
|
|
|
app_client_shm.shm->process_control_request
|
|
|
|
);
|
2004-08-11 11:30:25 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-02-03 20:48:48 +00:00
|
|
|
// Send an abort message.
|
|
|
|
//
|
|
|
|
int ACTIVE_TASK::request_abort() {
|
|
|
|
if (!app_client_shm.shm) return 1;
|
|
|
|
process_control_queue.msg_queue_send(
|
|
|
|
"<abort/>",
|
|
|
|
app_client_shm.shm->process_control_request
|
|
|
|
);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Kill the task by OS-specific means.
|
2004-08-11 11:30:25 +00:00
|
|
|
//
|
|
|
|
int ACTIVE_TASK::kill_task() {
|
|
|
|
#ifdef _WIN32
|
|
|
|
return !TerminateProcess(pid_handle, -1);
|
|
|
|
#else
|
|
|
|
return kill(pid, SIGKILL);
|
|
|
|
#endif
|
2005-02-25 21:31:46 +00:00
|
|
|
cleanup_task();
|
2004-08-11 11:30:25 +00:00
|
|
|
}
|
|
|
|
|
2004-08-23 22:06:48 +00:00
|
|
|
// We have sent a quit request to the process; see if it's exited.
|
2004-08-11 11:30:25 +00:00
|
|
|
// This is called when the core client exits,
|
|
|
|
// or when a project is detached or reset
|
|
|
|
//
|
2004-08-23 22:06:48 +00:00
|
|
|
bool ACTIVE_TASK::has_task_exited() {
|
2004-08-11 11:30:25 +00:00
|
|
|
bool exited = false;
|
2004-08-23 22:06:48 +00:00
|
|
|
|
|
|
|
if (!process_exists()) return true;
|
|
|
|
|
2004-08-11 11:30:25 +00:00
|
|
|
#ifdef _WIN32
|
|
|
|
unsigned long exit_code;
|
|
|
|
if (GetExitCodeProcess(pid_handle, &exit_code)) {
|
|
|
|
if (exit_code != STILL_ACTIVE) {
|
|
|
|
exited = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
2005-08-04 00:12:50 +00:00
|
|
|
// We don't use status
|
|
|
|
if (waitpid(pid, 0, WNOHANG) == pid) {
|
2004-08-11 11:30:25 +00:00
|
|
|
exited = true;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
if (exited) {
|
2005-01-21 23:26:36 +00:00
|
|
|
task_state = PROCESS_EXITED;
|
2005-02-25 21:31:46 +00:00
|
|
|
cleanup_task();
|
2004-08-11 11:30:25 +00:00
|
|
|
}
|
|
|
|
return exited;
|
|
|
|
}
|
|
|
|
|
2004-08-23 22:06:48 +00:00
|
|
|
// preempt this task
|
|
|
|
// called from the CLIENT_STATE::schedule_cpus()
|
2005-05-25 21:28:36 +00:00
|
|
|
// if quit_task is true do this by quitting
|
2004-08-11 11:30:25 +00:00
|
|
|
//
|
|
|
|
int ACTIVE_TASK::preempt(bool quit_task) {
|
|
|
|
int retval;
|
|
|
|
|
2005-05-25 21:28:36 +00:00
|
|
|
// If the app hasn't checkpoint yet, suspend instead of quit
|
|
|
|
// (accommodate apps that never checkpoint)
|
|
|
|
//
|
|
|
|
if (quit_task && (checkpoint_cpu_time>0)) {
|
2004-08-11 11:30:25 +00:00
|
|
|
pending_suspend_via_quit = true;
|
2005-12-06 03:18:02 +00:00
|
|
|
retval = request_exit();
|
2004-08-11 11:30:25 +00:00
|
|
|
} else {
|
|
|
|
retval = suspend();
|
|
|
|
}
|
|
|
|
|
|
|
|
scheduler_state = CPU_SCHED_PREEMPTED;
|
|
|
|
|
|
|
|
msg_printf(result->project, MSG_INFO,
|
2006-01-17 22:48:09 +00:00
|
|
|
"Pausing task %s (%s)",
|
2004-09-02 23:06:14 +00:00
|
|
|
result->name, (quit_task ? "removed from memory" : "left in memory")
|
2004-08-11 11:30:25 +00:00
|
|
|
);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-08-25 19:20:45 +00:00
|
|
|
static void limbo_message(ACTIVE_TASK& at) {
|
|
|
|
msg_printf(at.result->project, MSG_INFO,
|
2006-01-17 22:48:09 +00:00
|
|
|
"Task %s exited with zero status but no 'finished' file",
|
2004-08-25 19:20:45 +00:00
|
|
|
at.result->name
|
|
|
|
);
|
|
|
|
msg_printf(at.result->project, MSG_INFO,
|
2004-09-04 05:21:33 +00:00
|
|
|
"If this happens repeatedly you may need to reset the project."
|
2004-08-25 19:20:45 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2004-08-23 22:06:48 +00:00
|
|
|
// deal with a process that has exited, for whatever reason
|
|
|
|
// (including preemption)
|
|
|
|
//
|
2004-08-11 11:30:25 +00:00
|
|
|
#ifdef _WIN32
|
2005-12-09 07:50:35 +00:00
|
|
|
void ACTIVE_TASK::handle_exited_app(unsigned long exit_code) {
|
2005-04-05 00:32:24 +00:00
|
|
|
get_app_status_msg();
|
2004-08-24 21:44:54 +00:00
|
|
|
get_trickle_up_msg();
|
2005-03-30 21:11:49 +00:00
|
|
|
result->final_cpu_time = current_cpu_time;
|
2005-01-21 23:26:36 +00:00
|
|
|
if (task_state == PROCESS_ABORT_PENDING) {
|
|
|
|
task_state = PROCESS_ABORTED;
|
2004-08-11 11:30:25 +00:00
|
|
|
} else {
|
2005-01-21 23:26:36 +00:00
|
|
|
task_state = PROCESS_EXITED;
|
2004-08-11 11:30:25 +00:00
|
|
|
|
|
|
|
if (exit_code) {
|
|
|
|
char szError[1024];
|
|
|
|
gstate.report_result_error(
|
2004-10-07 19:18:37 +00:00
|
|
|
*result,
|
2004-08-11 11:30:25 +00:00
|
|
|
"%s - exit code %d (0x%x)",
|
|
|
|
windows_format_error_string(exit_code, szError, sizeof(szError)),
|
|
|
|
exit_code, exit_code
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
if (pending_suspend_via_quit) {
|
|
|
|
pending_suspend_via_quit = false;
|
2005-01-22 00:24:34 +00:00
|
|
|
task_state = PROCESS_UNINITIALIZED;
|
2004-09-04 05:21:33 +00:00
|
|
|
close_process_handles();
|
2005-12-09 07:50:35 +00:00
|
|
|
return;
|
2004-08-20 23:36:42 +00:00
|
|
|
}
|
|
|
|
if (!finish_file_present()) {
|
2004-09-04 19:33:54 +00:00
|
|
|
scheduler_state = CPU_SCHED_PREEMPTED;
|
2005-01-22 00:24:34 +00:00
|
|
|
task_state = PROCESS_UNINITIALIZED;
|
2004-09-04 05:21:33 +00:00
|
|
|
close_process_handles();
|
2004-08-25 19:20:45 +00:00
|
|
|
limbo_message(*this);
|
2005-12-09 07:50:35 +00:00
|
|
|
goto done;
|
2004-08-11 11:30:25 +00:00
|
|
|
}
|
|
|
|
}
|
2005-01-21 23:26:36 +00:00
|
|
|
result->exit_status = exit_code;
|
2004-08-11 11:30:25 +00:00
|
|
|
}
|
2004-09-01 04:59:32 +00:00
|
|
|
|
|
|
|
if (app_client_shm.shm) {
|
|
|
|
detach_shmem(shm_handle, app_client_shm.shm);
|
|
|
|
app_client_shm.shm = NULL;
|
|
|
|
}
|
|
|
|
|
2004-08-11 11:30:25 +00:00
|
|
|
read_stderr_file();
|
|
|
|
clean_out_dir(slot_dir);
|
2005-12-09 07:50:35 +00:00
|
|
|
done:
|
|
|
|
gstate.request_schedule_cpus("application exited");
|
2004-08-11 11:30:25 +00:00
|
|
|
}
|
|
|
|
#else
|
2005-12-09 07:50:35 +00:00
|
|
|
void ACTIVE_TASK::handle_exited_app(int stat) {
|
2004-08-11 11:30:25 +00:00
|
|
|
SCOPE_MSG_LOG scope_messages(log_messages, CLIENT_MSG_LOG::DEBUG_TASK);
|
|
|
|
|
2004-08-24 21:44:54 +00:00
|
|
|
get_app_status_msg();
|
|
|
|
get_trickle_up_msg();
|
2005-03-30 21:11:49 +00:00
|
|
|
result->final_cpu_time = current_cpu_time;
|
2005-01-21 23:26:36 +00:00
|
|
|
if (task_state == PROCESS_ABORT_PENDING) {
|
|
|
|
task_state = PROCESS_ABORTED;
|
2004-08-11 11:30:25 +00:00
|
|
|
} else {
|
|
|
|
if (WIFEXITED(stat)) {
|
2005-01-21 23:26:36 +00:00
|
|
|
task_state = PROCESS_EXITED;
|
|
|
|
result->exit_status = WEXITSTATUS(stat);
|
2004-08-11 11:30:25 +00:00
|
|
|
|
2005-01-21 23:26:36 +00:00
|
|
|
if (result->exit_status) {
|
2004-08-11 11:30:25 +00:00
|
|
|
gstate.report_result_error(
|
2004-10-07 19:18:37 +00:00
|
|
|
*result,
|
2004-08-11 11:30:25 +00:00
|
|
|
"process exited with code %d (0x%x)",
|
2005-01-21 23:26:36 +00:00
|
|
|
result->exit_status, result->exit_status
|
2004-08-11 11:30:25 +00:00
|
|
|
);
|
|
|
|
} else {
|
2004-08-20 23:36:42 +00:00
|
|
|
// check for cases where an app exits
|
|
|
|
// without it being done from core client's point of view;
|
|
|
|
// in these cases, don't clean out slot dir
|
|
|
|
//
|
2004-08-11 11:30:25 +00:00
|
|
|
if (pending_suspend_via_quit) {
|
|
|
|
pending_suspend_via_quit = false;
|
2005-01-21 23:26:36 +00:00
|
|
|
task_state = PROCESS_UNINITIALIZED;
|
2004-08-11 11:30:25 +00:00
|
|
|
|
|
|
|
// destroy shm, since restarting app will re-create it
|
|
|
|
//
|
2005-02-25 21:31:46 +00:00
|
|
|
cleanup_task();
|
2005-12-09 07:50:35 +00:00
|
|
|
return;
|
2004-08-20 23:36:42 +00:00
|
|
|
}
|
|
|
|
if (!finish_file_present()) {
|
2004-08-11 11:30:25 +00:00
|
|
|
// The process looks like it exited normally
|
|
|
|
// but there's no "finish file".
|
|
|
|
// Assume it was externally killed,
|
2004-11-18 22:18:00 +00:00
|
|
|
// and arrange for it to get restarted.
|
2004-08-11 11:30:25 +00:00
|
|
|
//
|
2004-09-04 19:33:54 +00:00
|
|
|
scheduler_state = CPU_SCHED_PREEMPTED;
|
2005-01-21 23:26:36 +00:00
|
|
|
task_state = PROCESS_UNINITIALIZED;
|
2005-02-25 21:31:46 +00:00
|
|
|
cleanup_task();
|
2004-08-25 19:20:45 +00:00
|
|
|
limbo_message(*this);
|
2005-12-09 07:50:35 +00:00
|
|
|
goto done;
|
2004-08-11 11:30:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
scope_messages.printf(
|
|
|
|
"ACTIVE_TASK::handle_exited_app(): process exited: status %d\n",
|
2005-01-21 23:26:36 +00:00
|
|
|
result->exit_status
|
2004-08-11 11:30:25 +00:00
|
|
|
);
|
|
|
|
} else if (WIFSIGNALED(stat)) {
|
2004-10-07 19:18:37 +00:00
|
|
|
int got_signal = WTERMSIG(stat);
|
2004-08-11 11:30:25 +00:00
|
|
|
|
|
|
|
// if the process was externally killed, allow it to restart.
|
|
|
|
//
|
2004-11-18 22:18:00 +00:00
|
|
|
switch (got_signal) {
|
2004-08-11 11:30:25 +00:00
|
|
|
case SIGHUP:
|
|
|
|
case SIGINT:
|
|
|
|
case SIGQUIT:
|
|
|
|
case SIGKILL:
|
|
|
|
case SIGTERM:
|
|
|
|
case SIGSTOP:
|
2004-11-18 22:18:00 +00:00
|
|
|
scheduler_state = CPU_SCHED_PREEMPTED;
|
2005-01-21 23:26:36 +00:00
|
|
|
task_state = PROCESS_UNINITIALIZED;
|
2004-08-25 19:20:45 +00:00
|
|
|
limbo_message(*this);
|
2005-12-09 07:50:35 +00:00
|
|
|
goto done;
|
2004-08-11 11:30:25 +00:00
|
|
|
}
|
2005-01-21 23:26:36 +00:00
|
|
|
result->exit_status = stat;
|
|
|
|
task_state = PROCESS_WAS_SIGNALED;
|
2004-10-07 19:18:37 +00:00
|
|
|
signal = got_signal;
|
2004-08-11 11:30:25 +00:00
|
|
|
gstate.report_result_error(
|
2004-10-07 19:18:37 +00:00
|
|
|
*result, "process got signal %d", signal
|
2004-08-11 11:30:25 +00:00
|
|
|
);
|
2005-01-21 23:26:36 +00:00
|
|
|
scope_messages.printf(
|
|
|
|
"ACTIVE_TASK::handle_exited_app(): process got signal %d\n",
|
|
|
|
signal
|
|
|
|
);
|
2004-08-11 11:30:25 +00:00
|
|
|
} else {
|
2005-01-21 23:26:36 +00:00
|
|
|
task_state = PROCESS_EXIT_UNKNOWN;
|
2004-08-11 11:30:25 +00:00
|
|
|
result->state = PROCESS_EXIT_UNKNOWN;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
read_stderr_file();
|
|
|
|
clean_out_dir(slot_dir);
|
2005-12-09 07:50:35 +00:00
|
|
|
done:
|
|
|
|
gstate.request_schedule_cpus("application exited");
|
2004-08-11 11:30:25 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
bool ACTIVE_TASK::finish_file_present() {
|
|
|
|
char path[256];
|
|
|
|
sprintf(path, "%s%s%s", slot_dir, PATH_SEPARATOR, BOINC_FINISH_CALLED_FILE);
|
2006-01-20 20:58:33 +00:00
|
|
|
return (boinc_file_exists(path) != 0);
|
2004-08-11 11:30:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ACTIVE_TASK_SET::send_trickle_downs() {
|
|
|
|
unsigned int i;
|
|
|
|
ACTIVE_TASK* atp;
|
|
|
|
bool sent;
|
|
|
|
for (i=0; i<active_tasks.size(); i++) {
|
|
|
|
atp = active_tasks[i];
|
2004-08-23 22:06:48 +00:00
|
|
|
if (!atp->process_exists()) continue;
|
2004-08-11 11:30:25 +00:00
|
|
|
if (atp->have_trickle_down) {
|
2004-08-24 21:44:54 +00:00
|
|
|
if (!atp->app_client_shm.shm) continue;
|
2004-08-11 11:30:25 +00:00
|
|
|
sent = atp->app_client_shm.shm->trickle_down.send_msg("<have_trickle_down/>\n");
|
|
|
|
if (sent) atp->have_trickle_down = false;
|
|
|
|
}
|
2005-04-28 23:19:58 +00:00
|
|
|
if (atp->send_upload_file_status) {
|
|
|
|
if (!atp->app_client_shm.shm) continue;
|
|
|
|
sent = atp->app_client_shm.shm->trickle_down.send_msg("<upload_file_status/>\n");
|
|
|
|
if (sent) atp->send_upload_file_status = false;
|
|
|
|
}
|
2004-08-11 11:30:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ACTIVE_TASK_SET::send_heartbeats() {
|
|
|
|
unsigned int i;
|
|
|
|
ACTIVE_TASK* atp;
|
|
|
|
|
|
|
|
for (i=0; i<active_tasks.size(); i++) {
|
|
|
|
atp = active_tasks[i];
|
2004-08-23 22:06:48 +00:00
|
|
|
if (!atp->process_exists()) continue;
|
2004-08-24 21:44:54 +00:00
|
|
|
if (!atp->app_client_shm.shm) continue;
|
2004-08-11 11:30:25 +00:00
|
|
|
atp->app_client_shm.shm->heartbeat.send_msg("<heartbeat/>\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-09-13 05:27:28 +00:00
|
|
|
void ACTIVE_TASK_SET::process_control_poll() {
|
|
|
|
unsigned int i;
|
|
|
|
ACTIVE_TASK* atp;
|
|
|
|
|
|
|
|
for (i=0; i<active_tasks.size(); i++) {
|
|
|
|
atp = active_tasks[i];
|
|
|
|
if (!atp->process_exists()) continue;
|
|
|
|
if (!atp->app_client_shm.shm) continue;
|
|
|
|
atp->process_control_queue.msg_queue_poll(
|
|
|
|
atp->app_client_shm.shm->process_control_request
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-08-23 22:06:48 +00:00
|
|
|
// See if any processes have exited
|
|
|
|
//
|
2004-08-11 11:30:25 +00:00
|
|
|
bool ACTIVE_TASK_SET::check_app_exited() {
|
|
|
|
ACTIVE_TASK* atp;
|
|
|
|
bool found = false;
|
|
|
|
|
|
|
|
SCOPE_MSG_LOG scope_messages(log_messages, CLIENT_MSG_LOG::DEBUG_TASK);
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
unsigned long exit_code;
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
for (i=0; i<active_tasks.size(); i++) {
|
|
|
|
atp = active_tasks[i];
|
2004-08-23 22:06:48 +00:00
|
|
|
if (!atp->process_exists()) continue;
|
2004-08-11 11:30:25 +00:00
|
|
|
if (GetExitCodeProcess(atp->pid_handle, &exit_code)) {
|
|
|
|
if (exit_code != STILL_ACTIVE) {
|
|
|
|
found = true;
|
|
|
|
atp->handle_exited_app(exit_code);
|
|
|
|
}
|
2005-11-09 01:51:36 +00:00
|
|
|
} else {
|
|
|
|
char errmsg[1024];
|
|
|
|
scope_messages.printf(
|
|
|
|
"ACTIVE_TASK_SET::check_app_exited(): task %s GetExitCodeProcess Failed - GLE %d (0x%x)",
|
|
|
|
windows_format_error_string(GetLastError(), errmsg, sizeof(errmsg)),
|
|
|
|
GetLastError(), GetLastError()
|
|
|
|
);
|
2004-08-11 11:30:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
2005-08-04 00:12:50 +00:00
|
|
|
int pid, stat;
|
2004-08-11 11:30:25 +00:00
|
|
|
|
2005-08-04 00:12:50 +00:00
|
|
|
if ((pid = waitpid(0, &stat, WNOHANG)) > 0) {
|
2004-08-11 11:30:25 +00:00
|
|
|
scope_messages.printf("ACTIVE_TASK_SET::check_app_exited(): process %d is done\n", pid);
|
|
|
|
atp = lookup_pid(pid);
|
|
|
|
if (!atp) {
|
2005-10-09 05:53:35 +00:00
|
|
|
// if we're running benchmarks, exited process
|
2005-12-09 07:50:35 +00:00
|
|
|
// is probably a benchmark process; don't show error
|
2005-10-09 05:53:35 +00:00
|
|
|
//
|
|
|
|
if (!gstate.are_cpu_benchmarks_running()) {
|
|
|
|
msg_printf(NULL, MSG_ERROR,
|
2006-01-17 22:48:09 +00:00
|
|
|
"Process %d not found\n",
|
2005-10-09 05:53:35 +00:00
|
|
|
pid
|
|
|
|
);
|
|
|
|
}
|
2004-08-11 11:30:25 +00:00
|
|
|
return false;
|
|
|
|
}
|
2004-09-22 21:08:26 +00:00
|
|
|
atp->handle_exited_app(stat);
|
2004-08-11 11:30:25 +00:00
|
|
|
found = true;
|
|
|
|
}
|
|
|
|
#endif
|
2004-09-24 22:19:02 +00:00
|
|
|
|
2004-08-11 11:30:25 +00:00
|
|
|
return found;
|
|
|
|
}
|
|
|
|
|
|
|
|
// if an app has exceeded its maximum CPU time, abort it
|
|
|
|
//
|
|
|
|
bool ACTIVE_TASK::check_max_cpu_exceeded() {
|
|
|
|
if (current_cpu_time > max_cpu_time) {
|
|
|
|
msg_printf(result->project, MSG_INFO,
|
2006-01-17 22:48:09 +00:00
|
|
|
"Aborting task %s: exceeded CPU time limit %f\n",
|
2004-08-11 11:30:25 +00:00
|
|
|
result->name, max_cpu_time
|
|
|
|
);
|
2005-06-25 23:54:07 +00:00
|
|
|
abort_task(ERR_RSC_LIMIT_EXCEEDED, "Maximum CPU time exceeded");
|
2004-08-11 11:30:25 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// if an app has exceeded its maximum disk usage, abort it
|
|
|
|
//
|
|
|
|
bool ACTIVE_TASK::check_max_disk_exceeded() {
|
|
|
|
double disk_usage;
|
|
|
|
int retval;
|
|
|
|
|
|
|
|
// don't do disk check too often
|
|
|
|
//
|
|
|
|
retval = current_disk_usage(disk_usage);
|
|
|
|
if (retval) {
|
2006-01-17 22:48:09 +00:00
|
|
|
msg_printf(0, MSG_ERROR,
|
|
|
|
"Can't get task disk usage: %s", boincerror(retval)
|
|
|
|
);
|
2004-08-11 11:30:25 +00:00
|
|
|
} else {
|
|
|
|
if (disk_usage > max_disk_usage) {
|
|
|
|
msg_printf(
|
|
|
|
result->project, MSG_INFO,
|
2006-01-17 22:48:09 +00:00
|
|
|
"Aborting task %s: exceeded disk limit: %f > %f\n",
|
2004-08-11 11:30:25 +00:00
|
|
|
result->name, disk_usage, max_disk_usage
|
|
|
|
);
|
2005-06-25 23:54:07 +00:00
|
|
|
abort_task(ERR_RSC_LIMIT_EXCEEDED, "Maximum disk usage exceeded");
|
2004-08-11 11:30:25 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
// if an app has exceeded its maximum allowed memory, abort it
|
|
|
|
//
|
|
|
|
bool ACTIVE_TASK::check_max_mem_exceeded() {
|
|
|
|
// TODO: calculate working set size elsewhere
|
|
|
|
if (working_set_size > max_mem_usage || working_set_size/1048576 > gstate.global_prefs.max_memory_mbytes) {
|
|
|
|
msg_printf(
|
|
|
|
result->project, MSG_INFO,
|
2006-01-17 22:48:09 +00:00
|
|
|
"Aborting task %s: exceeded memory limit %f\n",
|
2004-08-11 11:30:25 +00:00
|
|
|
result->name,
|
|
|
|
min(max_mem_usage, gstate.global_prefs.max_memory_mbytes*1048576)
|
|
|
|
);
|
2005-06-25 23:54:07 +00:00
|
|
|
abort_task(ERR_RSC_LIMIT_EXCEEDED, "Maximum memory usage exceeded");
|
2004-08-11 11:30:25 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
bool ACTIVE_TASK::check_max_mem_exceeded() {
|
2004-12-14 20:28:13 +00:00
|
|
|
if (max_mem_usage != 0 && rss_bytes > max_mem_usage) {
|
2004-08-11 11:30:25 +00:00
|
|
|
msg_printf(
|
|
|
|
result->project, MSG_INFO,
|
2006-01-17 22:48:09 +00:00
|
|
|
"Task %s: memory usage %f exceeds limit %f\n",
|
2004-08-11 11:30:25 +00:00
|
|
|
result->name,
|
2004-12-14 20:28:13 +00:00
|
|
|
rss_bytes,
|
2004-08-11 11:30:25 +00:00
|
|
|
max_mem_usage
|
|
|
|
);
|
2005-06-25 23:54:07 +00:00
|
|
|
//abort_task(ERR_RSC_LIMIT_EXCEEDED, "Maximum memory usage exceeded");
|
2004-08-11 11:30:25 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ACTIVE_TASK_SET::vm_limit_exceeded(double vm_limit) {
|
|
|
|
unsigned int i;
|
|
|
|
ACTIVE_TASK *atp;
|
|
|
|
|
|
|
|
double total_vm_usage = 0;
|
|
|
|
|
|
|
|
for (i=0; i<active_tasks.size(); ++i) {
|
|
|
|
atp = active_tasks[i];
|
2004-08-23 22:06:48 +00:00
|
|
|
if (!atp->process_exists()) continue;
|
2004-12-14 20:28:13 +00:00
|
|
|
total_vm_usage += atp->vm_bytes;
|
2004-08-11 11:30:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return (total_vm_usage > vm_limit);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if any of the active tasks have exceeded their
|
|
|
|
// resource limits on disk, CPU time or memory
|
|
|
|
//
|
|
|
|
bool ACTIVE_TASK_SET::check_rsc_limits_exceeded() {
|
|
|
|
unsigned int j;
|
|
|
|
ACTIVE_TASK *atp;
|
2004-11-15 21:20:58 +00:00
|
|
|
static double last_disk_check_time = 0;
|
2005-11-23 03:23:13 +00:00
|
|
|
bool do_disk_check = false;
|
|
|
|
bool did_anything = false;
|
2004-08-11 11:30:25 +00:00
|
|
|
|
2005-11-23 03:23:13 +00:00
|
|
|
// disk_interval is typically 60 sec,
|
|
|
|
// and some slot dirs have lots of files.
|
|
|
|
// So only check every 5*disk_interval
|
|
|
|
//
|
|
|
|
if (gstate.now > last_disk_check_time + 5*gstate.global_prefs.disk_interval) {
|
|
|
|
do_disk_check = true;
|
|
|
|
}
|
2004-08-11 11:30:25 +00:00
|
|
|
for (j=0;j<active_tasks.size();j++) {
|
|
|
|
atp = active_tasks[j];
|
2005-01-21 23:26:36 +00:00
|
|
|
if (atp->task_state != PROCESS_EXECUTING) continue;
|
2005-11-23 03:23:13 +00:00
|
|
|
if (atp->check_max_cpu_exceeded()) did_anything = true;
|
|
|
|
else if (atp->check_max_mem_exceeded()) did_anything = true;
|
|
|
|
else if (do_disk_check && atp->check_max_disk_exceeded()) {
|
|
|
|
did_anything = true;
|
2004-08-11 11:30:25 +00:00
|
|
|
}
|
|
|
|
}
|
2005-11-23 03:23:13 +00:00
|
|
|
if (do_disk_check) {
|
|
|
|
last_disk_check_time = gstate.now;
|
|
|
|
}
|
|
|
|
return did_anything;
|
2004-08-11 11:30:25 +00:00
|
|
|
}
|
|
|
|
|
2006-02-03 20:48:48 +00:00
|
|
|
// 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.
|
2004-08-11 11:30:25 +00:00
|
|
|
//
|
2005-06-25 23:54:07 +00:00
|
|
|
int ACTIVE_TASK::abort_task(int exit_status, const char* msg) {
|
2005-01-21 23:26:36 +00:00
|
|
|
if (task_state == PROCESS_EXECUTING || task_state == PROCESS_SUSPENDED) {
|
|
|
|
task_state = PROCESS_ABORT_PENDING;
|
2006-02-03 20:48:48 +00:00
|
|
|
abort_time = gstate.now;
|
|
|
|
request_abort();
|
2004-08-11 11:30:25 +00:00
|
|
|
} else {
|
2005-01-21 23:26:36 +00:00
|
|
|
task_state = PROCESS_ABORTED;
|
2004-08-11 11:30:25 +00:00
|
|
|
}
|
2005-06-25 23:54:07 +00:00
|
|
|
result->exit_status = exit_status;
|
2004-10-07 19:18:37 +00:00
|
|
|
gstate.report_result_error(*result, msg);
|
2004-08-11 11:30:25 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// check for the stderr file, copy to result record
|
|
|
|
//
|
|
|
|
bool ACTIVE_TASK::read_stderr_file() {
|
2005-02-08 00:53:26 +00:00
|
|
|
std::string stderr_file;
|
2004-08-11 11:30:25 +00:00
|
|
|
char path[256];
|
|
|
|
|
|
|
|
sprintf(path, "%s%s%s", slot_dir, PATH_SEPARATOR, STDERR_FILE);
|
2005-02-08 00:53:26 +00:00
|
|
|
if (boinc_file_exists(path) && !read_file_string(path, stderr_file)) {
|
|
|
|
// truncate stderr output to 63KB;
|
2004-08-11 11:30:25 +00:00
|
|
|
// it's unlikely that more than that will be useful
|
|
|
|
//
|
2005-02-08 19:30:07 +00:00
|
|
|
int max_len = 63*1024;
|
|
|
|
int len = stderr_file.length();
|
|
|
|
if (len > max_len) {
|
|
|
|
stderr_file = stderr_file.substr(len-max_len, len);
|
|
|
|
}
|
2005-02-08 00:53:26 +00:00
|
|
|
result->stderr_out += "<stderr_txt>\n";
|
|
|
|
result->stderr_out += stderr_file;
|
|
|
|
result->stderr_out += "\n</stderr_txt>\n";
|
2004-08-11 11:30:25 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// tell a running app to reread project preferences.
|
|
|
|
// This is called when project prefs change,
|
|
|
|
// or when a user file has finished downloading.
|
|
|
|
//
|
|
|
|
int ACTIVE_TASK::request_reread_prefs() {
|
|
|
|
int retval;
|
|
|
|
|
|
|
|
link_user_files();
|
|
|
|
|
2004-08-31 21:02:17 +00:00
|
|
|
retval = write_app_init_file();
|
2004-08-11 11:30:25 +00:00
|
|
|
if (retval) return retval;
|
2005-05-20 00:48:52 +00:00
|
|
|
graphics_request_queue.msg_queue_send(
|
|
|
|
xml_graphics_modes[MODE_REREAD_PREFS],
|
|
|
|
app_client_shm.shm->graphics_request
|
|
|
|
);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// tell a running app to reread the app_info file
|
|
|
|
// (e.g. because proxy settings have changed: this is for F@h)
|
|
|
|
//
|
|
|
|
int ACTIVE_TASK::request_reread_app_info() {
|
|
|
|
int retval = write_app_init_file();
|
|
|
|
if (retval) return retval;
|
|
|
|
process_control_queue.msg_queue_send(
|
|
|
|
"<reread_app_info/>",
|
|
|
|
app_client_shm.shm->process_control_request
|
2004-08-11 11:30:25 +00:00
|
|
|
);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// tell all running apps of a project to reread prefs
|
|
|
|
//
|
|
|
|
void ACTIVE_TASK_SET::request_reread_prefs(PROJECT* project) {
|
|
|
|
unsigned int i;
|
|
|
|
ACTIVE_TASK* atp;
|
|
|
|
|
|
|
|
for (i=0; i<active_tasks.size(); i++) {
|
|
|
|
atp = active_tasks[i];
|
|
|
|
if (atp->result->project != project) continue;
|
2004-08-23 22:06:48 +00:00
|
|
|
if (!atp->process_exists()) continue;
|
2004-08-11 11:30:25 +00:00
|
|
|
atp->request_reread_prefs();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-05-20 00:48:52 +00:00
|
|
|
void ACTIVE_TASK_SET::request_reread_app_info() {
|
|
|
|
for (unsigned int i=0; i<active_tasks.size(); i++) {
|
|
|
|
ACTIVE_TASK* atp = active_tasks[i];
|
|
|
|
if (!atp->process_exists()) continue;
|
|
|
|
atp->request_reread_app_info();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-08-11 11:30:25 +00:00
|
|
|
|
|
|
|
// send quit signal to all tasks in the project
|
|
|
|
// (or all tasks, if proj==0).
|
|
|
|
// If they don't exit in 5 seconds,
|
|
|
|
// send them a kill signal and wait up to 5 more seconds to exit.
|
|
|
|
// This is called when the core client exits,
|
|
|
|
// or when a project is detached or reset
|
|
|
|
//
|
|
|
|
int ACTIVE_TASK_SET::exit_tasks(PROJECT* proj) {
|
|
|
|
request_tasks_exit(proj);
|
|
|
|
|
|
|
|
// Wait 5 seconds for them to exit normally; if they don't then kill them
|
|
|
|
//
|
|
|
|
if (wait_for_exit(5, proj)) {
|
|
|
|
kill_tasks(proj);
|
|
|
|
}
|
|
|
|
wait_for_exit(5, proj);
|
|
|
|
|
|
|
|
// get final checkpoint_cpu_times
|
|
|
|
//
|
|
|
|
get_msgs();
|
|
|
|
|
2005-04-14 04:25:56 +00:00
|
|
|
gstate.request_schedule_cpus("exit_tasks");
|
2004-08-11 11:30:25 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Wait up to wait_time seconds for processes to exit
|
|
|
|
// If proj is zero, wait for all processes, else that project's
|
|
|
|
// NOTE: it's bad form to sleep, but it would be complex to avoid it here
|
|
|
|
//
|
|
|
|
int ACTIVE_TASK_SET::wait_for_exit(double wait_time, PROJECT* proj) {
|
|
|
|
bool all_exited;
|
|
|
|
unsigned int i,n;
|
|
|
|
ACTIVE_TASK *atp;
|
|
|
|
|
|
|
|
for (i=0; i<10; i++) {
|
|
|
|
all_exited = true;
|
|
|
|
|
|
|
|
for (n=0; n<active_tasks.size(); n++) {
|
|
|
|
atp = active_tasks[n];
|
|
|
|
if (proj && atp->wup->project != proj) continue;
|
2004-08-23 22:06:48 +00:00
|
|
|
if (!atp->has_task_exited()) {
|
2004-08-11 11:30:25 +00:00
|
|
|
all_exited = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (all_exited) return 0;
|
|
|
|
boinc_sleep(wait_time/10.0);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ERR_NOT_EXITED;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ACTIVE_TASK_SET::abort_project(PROJECT* project) {
|
|
|
|
vector<ACTIVE_TASK*>::iterator task_iter;
|
|
|
|
ACTIVE_TASK* atp;
|
|
|
|
|
|
|
|
exit_tasks(project);
|
|
|
|
task_iter = active_tasks.begin();
|
|
|
|
while (task_iter != active_tasks.end()) {
|
|
|
|
atp = *task_iter;
|
|
|
|
if (atp->result->project == project) {
|
|
|
|
task_iter = active_tasks.erase(task_iter);
|
|
|
|
delete atp;
|
|
|
|
} else {
|
|
|
|
task_iter++;
|
|
|
|
}
|
|
|
|
}
|
2005-04-13 18:38:55 +00:00
|
|
|
project->long_term_debt = 0;
|
2004-08-11 11:30:25 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Find the ACTIVE_TASK in the current set with the matching PID
|
|
|
|
//
|
|
|
|
ACTIVE_TASK* ACTIVE_TASK_SET::lookup_pid(int pid) {
|
|
|
|
unsigned int i;
|
|
|
|
ACTIVE_TASK* atp;
|
|
|
|
|
|
|
|
for (i=0; i<active_tasks.size(); i++) {
|
|
|
|
atp = active_tasks[i];
|
|
|
|
if (atp->pid == pid) return atp;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Find the ACTIVE_TASK in the current set with the matching result
|
|
|
|
//
|
|
|
|
ACTIVE_TASK* ACTIVE_TASK_SET::lookup_result(RESULT* result) {
|
2004-08-23 22:06:48 +00:00
|
|
|
unsigned int i;
|
|
|
|
ACTIVE_TASK* atp;
|
|
|
|
|
|
|
|
for (i=0; i<active_tasks.size(); i++) {
|
|
|
|
atp = active_tasks[i];
|
2004-08-11 11:30:25 +00:00
|
|
|
if (atp->result == result) {
|
|
|
|
return atp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// suspend all currently running tasks
|
2004-08-23 22:06:48 +00:00
|
|
|
// called only from CLIENT_STATE::suspend_activities(),
|
|
|
|
// e.g. because on batteries, time of day, benchmarking, etc.
|
2004-08-11 11:30:25 +00:00
|
|
|
//
|
|
|
|
void ACTIVE_TASK_SET::suspend_all(bool leave_apps_in_memory) {
|
|
|
|
unsigned int i;
|
|
|
|
ACTIVE_TASK* atp;
|
|
|
|
for (i=0; i<active_tasks.size(); i++) {
|
|
|
|
atp = active_tasks[i];
|
2005-01-21 23:26:36 +00:00
|
|
|
if (atp->task_state != PROCESS_EXECUTING) continue;
|
2005-08-17 21:05:26 +00:00
|
|
|
if (atp->non_cpu_intensive) continue;
|
2005-05-05 22:28:17 +00:00
|
|
|
atp->preempt(!leave_apps_in_memory);
|
2004-08-11 11:30:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// resume all currently running tasks
|
|
|
|
//
|
|
|
|
void ACTIVE_TASK_SET::unsuspend_all() {
|
|
|
|
unsigned int i;
|
|
|
|
ACTIVE_TASK* atp;
|
|
|
|
for (i=0; i<active_tasks.size(); i++) {
|
|
|
|
atp = active_tasks[i];
|
2005-08-17 21:05:26 +00:00
|
|
|
if (atp->non_cpu_intensive) continue;
|
2004-08-23 22:06:48 +00:00
|
|
|
if (atp->scheduler_state != CPU_SCHED_SCHEDULED) continue;
|
2005-01-21 23:26:36 +00:00
|
|
|
if (atp->task_state == PROCESS_UNINITIALIZED) {
|
2004-08-11 11:30:25 +00:00
|
|
|
if (atp->start(false)) {
|
2006-01-17 22:48:09 +00:00
|
|
|
msg_printf(atp->wup->project, MSG_ERROR,
|
|
|
|
"Couldn't restart task %s", atp->result->name
|
2004-08-11 11:30:25 +00:00
|
|
|
);
|
|
|
|
}
|
2005-01-21 23:26:36 +00:00
|
|
|
} else if (atp->task_state == PROCESS_SUSPENDED) {
|
2004-08-23 22:06:48 +00:00
|
|
|
atp->unsuspend();
|
2004-08-11 11:30:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check to see if any tasks are running
|
2004-08-23 22:06:48 +00:00
|
|
|
// called if benchmarking and waiting for suspends to happen
|
2004-08-11 11:30:25 +00:00
|
|
|
//
|
2004-08-23 22:06:48 +00:00
|
|
|
bool ACTIVE_TASK_SET::is_task_executing() {
|
2004-08-11 11:30:25 +00:00
|
|
|
unsigned int i;
|
|
|
|
ACTIVE_TASK* atp;
|
|
|
|
for (i=0; i<active_tasks.size(); i++) {
|
|
|
|
atp = active_tasks[i];
|
2005-01-21 23:26:36 +00:00
|
|
|
if (atp->task_state == PROCESS_EXECUTING) {
|
2004-08-11 11:30:25 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2005-02-25 21:31:46 +00:00
|
|
|
// Send quit message to all app processes
|
2004-08-11 11:30:25 +00:00
|
|
|
// This is called when the core client exits,
|
|
|
|
// or when a project is detached or reset
|
|
|
|
//
|
|
|
|
void ACTIVE_TASK_SET::request_tasks_exit(PROJECT* proj) {
|
|
|
|
unsigned int i;
|
|
|
|
ACTIVE_TASK *atp;
|
|
|
|
for (i=0; i<active_tasks.size(); i++) {
|
|
|
|
atp = active_tasks[i];
|
|
|
|
if (proj && atp->wup->project != proj) continue;
|
2004-08-23 22:06:48 +00:00
|
|
|
if (!atp->process_exists()) continue;
|
2004-08-11 11:30:25 +00:00
|
|
|
atp->request_exit();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-08-23 22:06:48 +00:00
|
|
|
// Send kill signal to all app processes
|
2004-08-11 11:30:25 +00:00
|
|
|
// Don't wait for them to exit
|
|
|
|
//
|
|
|
|
void ACTIVE_TASK_SET::kill_tasks(PROJECT* proj) {
|
|
|
|
unsigned int i;
|
|
|
|
ACTIVE_TASK *atp;
|
|
|
|
for (i=0; i<active_tasks.size(); i++) {
|
|
|
|
atp = active_tasks[i];
|
|
|
|
if (proj && atp->wup->project != proj) continue;
|
2004-08-23 22:06:48 +00:00
|
|
|
if (!atp->process_exists()) continue;
|
2004-08-11 11:30:25 +00:00
|
|
|
atp->kill_task();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-06-25 23:54:07 +00:00
|
|
|
// send a <suspend> message
|
2004-08-11 11:30:25 +00:00
|
|
|
//
|
|
|
|
int ACTIVE_TASK::suspend() {
|
2004-08-24 21:44:54 +00:00
|
|
|
if (!app_client_shm.shm) return 0;
|
2004-09-13 05:27:28 +00:00
|
|
|
process_control_queue.msg_queue_send(
|
|
|
|
"<suspend/>",
|
|
|
|
app_client_shm.shm->process_control_request
|
|
|
|
);
|
2005-01-21 23:26:36 +00:00
|
|
|
task_state = PROCESS_SUSPENDED;
|
2004-08-11 11:30:25 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// resume a suspended task
|
|
|
|
//
|
|
|
|
int ACTIVE_TASK::unsuspend() {
|
2004-08-24 21:44:54 +00:00
|
|
|
if (!app_client_shm.shm) return 0;
|
2004-09-13 05:27:28 +00:00
|
|
|
process_control_queue.msg_queue_send(
|
|
|
|
"<resume/>",
|
|
|
|
app_client_shm.shm->process_control_request
|
|
|
|
);
|
2005-01-21 23:26:36 +00:00
|
|
|
task_state = PROCESS_EXECUTING;
|
2004-08-11 11:30:25 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-08-17 22:08:35 +00:00
|
|
|
void ACTIVE_TASK::send_network_available() {
|
|
|
|
if (!app_client_shm.shm) return;
|
|
|
|
process_control_queue.msg_queue_send(
|
|
|
|
"<network_available/>",
|
|
|
|
app_client_shm.shm->process_control_request
|
|
|
|
);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2004-08-11 11:30:25 +00:00
|
|
|
// See if the app has placed a new message in shared mem
|
|
|
|
// (with CPU done, frac done etc.)
|
|
|
|
// If so parse it and return true.
|
|
|
|
//
|
2004-08-24 21:44:54 +00:00
|
|
|
bool ACTIVE_TASK::get_app_status_msg() {
|
2004-08-11 11:30:25 +00:00
|
|
|
char msg_buf[MSG_CHANNEL_SIZE];
|
2005-11-30 22:52:23 +00:00
|
|
|
int new_non_cpu_intensive;
|
2004-08-11 11:30:25 +00:00
|
|
|
|
2005-03-30 21:11:49 +00:00
|
|
|
if (!app_client_shm.shm) {
|
|
|
|
msg_printf(result->project, MSG_INFO,
|
2006-01-17 22:48:09 +00:00
|
|
|
"Task %s: no shared memory segment", result->name
|
2005-03-30 21:11:49 +00:00
|
|
|
);
|
|
|
|
return false;
|
|
|
|
}
|
2005-11-30 22:52:23 +00:00
|
|
|
if (!app_client_shm.shm->app_status.get_msg(msg_buf)) {
|
2005-03-30 21:11:49 +00:00
|
|
|
return false;
|
2004-08-11 11:30:25 +00:00
|
|
|
}
|
2006-02-01 22:41:03 +00:00
|
|
|
want_network = 0;
|
2005-11-30 22:52:23 +00:00
|
|
|
fraction_done = current_cpu_time = checkpoint_cpu_time = 0.0;
|
|
|
|
parse_double(msg_buf, "<fraction_done>", fraction_done);
|
|
|
|
parse_double(msg_buf, "<current_cpu_time>", current_cpu_time);
|
|
|
|
parse_double(msg_buf, "<checkpoint_cpu_time>", checkpoint_cpu_time);
|
|
|
|
parse_double(msg_buf, "<vm_bytes>", vm_bytes);
|
|
|
|
parse_double(msg_buf, "<rss_bytes>", rss_bytes);
|
|
|
|
parse_double(msg_buf, "<fpops_per_cpu_sec>", result->fpops_per_cpu_sec);
|
|
|
|
parse_double(msg_buf, "<fpops_cumulative>", result->fpops_cumulative);
|
|
|
|
parse_double(msg_buf, "<intops_per_cpu_sec>", result->intops_per_cpu_sec);
|
|
|
|
parse_double(msg_buf, "<intops_cumulative>", result->intops_cumulative);
|
2006-02-01 22:41:03 +00:00
|
|
|
parse_int(msg_buf, "<want_network>", want_network);
|
2005-12-02 19:38:29 +00:00
|
|
|
if (parse_int(msg_buf, "<non_cpu_intensive>", new_non_cpu_intensive)) {
|
|
|
|
if (new_non_cpu_intensive != non_cpu_intensive) {
|
|
|
|
non_cpu_intensive = new_non_cpu_intensive;
|
|
|
|
gstate.request_schedule_cpus("Change in app CPU-intensive status");
|
|
|
|
}
|
2005-11-30 22:52:23 +00:00
|
|
|
}
|
2005-03-30 21:11:49 +00:00
|
|
|
return true;
|
2004-08-24 21:44:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool ACTIVE_TASK::get_trickle_up_msg() {
|
|
|
|
char msg_buf[MSG_CHANNEL_SIZE];
|
|
|
|
bool found = false;
|
|
|
|
int retval;
|
|
|
|
|
|
|
|
if (!app_client_shm.shm) return false;
|
2004-08-11 11:30:25 +00:00
|
|
|
if (app_client_shm.shm->trickle_up.get_msg(msg_buf)) {
|
|
|
|
if (match_tag(msg_buf, "<have_new_trickle_up/>")) {
|
|
|
|
retval = move_trickle_file();
|
|
|
|
if (!retval) {
|
2005-08-15 05:08:42 +00:00
|
|
|
wup->project->trickle_up_pending = true;
|
2004-08-11 11:30:25 +00:00
|
|
|
}
|
|
|
|
}
|
2005-04-27 06:55:28 +00:00
|
|
|
if (match_tag(msg_buf, "<have_new_upload_file/>")) {
|
|
|
|
handle_upload_files();
|
|
|
|
}
|
2004-08-11 11:30:25 +00:00
|
|
|
found = true;
|
|
|
|
}
|
|
|
|
return found;
|
|
|
|
}
|
|
|
|
|
|
|
|
// check for msgs from active tasks.
|
|
|
|
// Return true if any of them has changed its checkpoint_cpu_time
|
|
|
|
// (since in that case we need to write state file)
|
|
|
|
//
|
|
|
|
bool ACTIVE_TASK_SET::get_msgs() {
|
|
|
|
unsigned int i;
|
|
|
|
ACTIVE_TASK *atp;
|
2004-10-21 21:52:33 +00:00
|
|
|
double old_time;
|
2004-08-11 11:30:25 +00:00
|
|
|
bool action = false;
|
|
|
|
|
|
|
|
for (i=0; i<active_tasks.size(); i++) {
|
|
|
|
atp = active_tasks[i];
|
2004-08-23 22:06:48 +00:00
|
|
|
if (!atp->process_exists()) continue;
|
2004-08-11 11:30:25 +00:00
|
|
|
old_time = atp->checkpoint_cpu_time;
|
2004-08-24 21:44:54 +00:00
|
|
|
if (atp->get_app_status_msg()) {
|
2004-08-11 11:30:25 +00:00
|
|
|
if (old_time != atp->checkpoint_cpu_time) {
|
|
|
|
action = true;
|
|
|
|
}
|
|
|
|
}
|
2004-08-24 21:44:54 +00:00
|
|
|
atp->get_trickle_up_msg();
|
2004-08-11 11:30:25 +00:00
|
|
|
}
|
|
|
|
return action;
|
|
|
|
}
|
2004-12-08 00:40:19 +00:00
|
|
|
|
2005-01-02 18:29:53 +00:00
|
|
|
const char *BOINC_RCSID_10ca137461 = "$Id$";
|