2005-01-20 23:22:22 +00:00
|
|
|
// Berkeley Open Infrastructure for Network Computing
|
|
|
|
// http://boinc.berkeley.edu
|
|
|
|
// Copyright (C) 2005 University of California
|
2003-07-02 02:02:18 +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.
|
2003-07-02 02:02:18 +00:00
|
|
|
//
|
2005-01-20 23:22:22 +00:00
|
|
|
// 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.
|
2002-04-30 22:22:54 +00:00
|
|
|
//
|
2005-01-20 23:22:22 +00:00
|
|
|
// 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
|
2002-04-30 22:22:54 +00:00
|
|
|
|
|
|
|
// Abstraction of a set of executing applications,
|
|
|
|
// connected to I/O files in various ways.
|
|
|
|
// Shouldn't depend on CLIENT_STATE.
|
|
|
|
|
2003-10-16 19:03:49 +00:00
|
|
|
#include "cpp.h"
|
2002-06-06 18:42:01 +00:00
|
|
|
|
|
|
|
#ifdef _WIN32
|
2004-06-16 23:16:08 +00:00
|
|
|
#include "boinc_win.h"
|
2005-11-21 18:34:44 +00:00
|
|
|
#else
|
|
|
|
#include "config.h"
|
2002-07-05 19:20:00 +00:00
|
|
|
#endif
|
2004-03-04 11:41:43 +00:00
|
|
|
|
|
|
|
#ifndef _WIN32
|
|
|
|
|
2002-07-05 19:20:00 +00:00
|
|
|
#if HAVE_UNISTD_H
|
2002-04-30 22:22:54 +00:00
|
|
|
#include <unistd.h>
|
2002-07-05 19:20:00 +00:00
|
|
|
#endif
|
|
|
|
#if HAVE_SYS_WAIT_H
|
2002-04-30 22:22:54 +00:00
|
|
|
#include <sys/wait.h>
|
2002-07-05 19:20:00 +00:00
|
|
|
#endif
|
|
|
|
#if HAVE_SYS_TIME_H
|
2002-05-22 15:52:26 +00:00
|
|
|
#include <sys/time.h>
|
2002-07-05 19:20:00 +00:00
|
|
|
#endif
|
|
|
|
#if HAVE_SYS_RESOURCE_H
|
2002-04-30 22:22:54 +00:00
|
|
|
#include <sys/resource.h>
|
2002-06-06 18:42:01 +00:00
|
|
|
#endif
|
2002-07-05 19:20:00 +00:00
|
|
|
#if HAVE_SYS_TYPES_H
|
2002-06-06 18:42:01 +00:00
|
|
|
#include <sys/types.h>
|
2002-07-05 19:20:00 +00:00
|
|
|
#endif
|
|
|
|
#if HAVE_FCNTL_H
|
2002-04-30 22:22:54 +00:00
|
|
|
#include <fcntl.h>
|
2002-07-05 19:20:00 +00:00
|
|
|
#endif
|
2002-07-15 23:21:20 +00:00
|
|
|
|
2004-07-13 13:54:09 +00:00
|
|
|
#include <cctype>
|
|
|
|
#include <ctime>
|
|
|
|
#include <cstdio>
|
|
|
|
#include <cmath>
|
|
|
|
#include <cstdlib>
|
2002-04-30 22:22:54 +00:00
|
|
|
|
2004-03-04 11:41:43 +00:00
|
|
|
#endif
|
|
|
|
|
2002-04-30 22:22:54 +00:00
|
|
|
#include "client_state.h"
|
2002-07-15 23:21:20 +00:00
|
|
|
#include "client_types.h"
|
2003-10-16 19:03:49 +00:00
|
|
|
#include "error_numbers.h"
|
2002-04-30 22:22:54 +00:00
|
|
|
#include "filesys.h"
|
|
|
|
#include "file_names.h"
|
|
|
|
#include "parse.h"
|
2003-03-17 19:24:38 +00:00
|
|
|
#include "shmem.h"
|
2002-07-22 23:07:14 +00:00
|
|
|
#include "util.h"
|
2004-04-08 08:15:23 +00:00
|
|
|
#include "client_msgs.h"
|
2006-08-28 18:22:07 +00:00
|
|
|
#include "procinfo.h"
|
2002-04-30 22:22:54 +00:00
|
|
|
#include "app.h"
|
2002-07-31 19:05:15 +00:00
|
|
|
|
2004-06-30 18:17:21 +00:00
|
|
|
using std::max;
|
2004-07-02 03:20:17 +00:00
|
|
|
using std::min;
|
2004-06-30 18:17:21 +00:00
|
|
|
|
2002-04-30 22:22:54 +00:00
|
|
|
ACTIVE_TASK::ACTIVE_TASK() {
|
|
|
|
result = NULL;
|
|
|
|
wup = NULL;
|
|
|
|
app_version = NULL;
|
2002-07-15 23:21:20 +00:00
|
|
|
pid = 0;
|
2002-04-30 22:22:54 +00:00
|
|
|
slot = 0;
|
2005-01-21 23:26:36 +00:00
|
|
|
task_state = PROCESS_UNINITIALIZED;
|
2004-06-30 01:10:22 +00:00
|
|
|
scheduler_state = CPU_SCHED_UNINITIALIZED;
|
2002-04-30 22:22:54 +00:00
|
|
|
signal = 0;
|
2003-03-19 01:15:46 +00:00
|
|
|
strcpy(slot_dir, "");
|
2004-09-13 05:27:28 +00:00
|
|
|
is_ss_app = false;
|
2004-07-18 04:41:27 +00:00
|
|
|
graphics_mode_acked = MODE_UNSUPPORTED;
|
2003-05-09 20:33:57 +00:00
|
|
|
graphics_mode_before_ss = MODE_HIDE_GRAPHICS;
|
2006-02-21 12:22:23 +00:00
|
|
|
graphics_mode_ack_timeout = 0;
|
|
|
|
exit_requested = false;
|
2004-04-03 01:26:40 +00:00
|
|
|
fraction_done = 0;
|
2004-05-21 20:06:34 +00:00
|
|
|
episode_start_cpu_time = 0;
|
2006-08-22 20:58:57 +00:00
|
|
|
run_interval_start_wall_time = gstate.now;
|
|
|
|
debt_interval_start_cpu_time = 0;
|
2004-08-11 11:30:25 +00:00
|
|
|
checkpoint_cpu_time = 0;
|
2006-06-15 23:15:27 +00:00
|
|
|
checkpoint_wall_time = 0;
|
2004-08-11 11:30:25 +00:00
|
|
|
current_cpu_time = 0;
|
|
|
|
have_trickle_down = false;
|
2005-04-28 23:19:58 +00:00
|
|
|
send_upload_file_status = false;
|
2004-08-11 11:30:25 +00:00
|
|
|
pending_suspend_via_quit = false;
|
2006-11-01 23:36:13 +00:00
|
|
|
too_large = false;
|
2005-08-17 22:08:35 +00:00
|
|
|
want_network = 0;
|
2006-11-01 23:36:13 +00:00
|
|
|
memset(&procinfo, 0, sizeof(procinfo));
|
2004-08-11 11:30:25 +00:00
|
|
|
#ifdef _WIN32
|
|
|
|
pid_handle = 0;
|
|
|
|
thread_handle = 0;
|
|
|
|
shm_handle = 0;
|
|
|
|
#endif
|
2003-10-30 23:23:52 +00:00
|
|
|
}
|
|
|
|
|
2004-08-11 11:30:25 +00:00
|
|
|
#ifdef _WIN32
|
2005-02-25 21:31:46 +00:00
|
|
|
|
|
|
|
// call this when a process has existed but will be started again
|
|
|
|
// (e.g. suspend via quit, exited but no finish file).
|
|
|
|
// In these cases we want to keep the shmem and events
|
|
|
|
//
|
2004-09-04 05:21:33 +00:00
|
|
|
void ACTIVE_TASK::close_process_handles() {
|
2004-09-02 22:34:35 +00:00
|
|
|
if (pid_handle) {
|
|
|
|
CloseHandle(pid_handle);
|
|
|
|
pid_handle = NULL;
|
|
|
|
}
|
|
|
|
if (thread_handle) {
|
|
|
|
CloseHandle(thread_handle);
|
|
|
|
thread_handle = NULL;
|
|
|
|
}
|
2004-09-04 05:21:33 +00:00
|
|
|
}
|
2005-02-25 21:31:46 +00:00
|
|
|
#endif
|
2004-09-04 05:21:33 +00:00
|
|
|
|
2005-02-25 21:31:46 +00:00
|
|
|
// call this when a process has exited and we're not going to restart it
|
|
|
|
//
|
|
|
|
void ACTIVE_TASK::cleanup_task() {
|
|
|
|
#ifdef _WIN32
|
2004-09-04 05:21:33 +00:00
|
|
|
close_process_handles();
|
2006-07-22 18:24:01 +00:00
|
|
|
|
2004-08-11 11:30:25 +00:00
|
|
|
// detach from shared mem.
|
|
|
|
// This will destroy shmem seg since we're the last attachment
|
2003-05-22 20:47:56 +00:00
|
|
|
//
|
2004-08-11 11:30:25 +00:00
|
|
|
if (app_client_shm.shm) {
|
|
|
|
detach_shmem(shm_handle, app_client_shm.shm);
|
|
|
|
app_client_shm.shm = NULL;
|
2003-05-22 20:47:56 +00:00
|
|
|
}
|
2004-08-11 11:30:25 +00:00
|
|
|
#else
|
2005-02-25 21:31:46 +00:00
|
|
|
int retval;
|
|
|
|
|
2004-08-11 11:30:25 +00:00
|
|
|
if (app_client_shm.shm) {
|
2005-02-25 21:31:46 +00:00
|
|
|
retval = detach_shmem(app_client_shm.shm);
|
|
|
|
if (retval) {
|
2006-06-05 04:30:16 +00:00
|
|
|
msg_printf(NULL, MSG_ERROR,
|
|
|
|
"Couldn't detach shared memory: %s", boincerror(retval)
|
|
|
|
);
|
2005-02-25 21:31:46 +00:00
|
|
|
}
|
|
|
|
retval = destroy_shmem(shmem_seg_name);
|
|
|
|
if (retval) {
|
2006-06-05 04:30:16 +00:00
|
|
|
msg_printf(NULL, MSG_ERROR,
|
|
|
|
"Couldn't destroy shared memory: %s", boincerror(retval)
|
|
|
|
);
|
2005-02-25 21:31:46 +00:00
|
|
|
}
|
2004-08-11 11:30:25 +00:00
|
|
|
app_client_shm.shm = NULL;
|
2003-03-11 22:18:01 +00:00
|
|
|
}
|
2005-02-25 21:31:46 +00:00
|
|
|
#endif
|
2003-03-11 22:18:01 +00:00
|
|
|
}
|
|
|
|
|
2004-09-04 05:21:33 +00:00
|
|
|
ACTIVE_TASK::~ACTIVE_TASK() {
|
2005-02-25 21:31:46 +00:00
|
|
|
cleanup_task();
|
2004-09-04 05:21:33 +00:00
|
|
|
}
|
|
|
|
|
2004-08-11 11:30:25 +00:00
|
|
|
int ACTIVE_TASK::init(RESULT* rp) {
|
|
|
|
result = rp;
|
|
|
|
wup = rp->wup;
|
|
|
|
app_version = wup->avp;
|
|
|
|
max_cpu_time = rp->wup->rsc_fpops_bound/gstate.host_info.p_fpops;
|
|
|
|
max_disk_usage = rp->wup->rsc_disk_bound;
|
|
|
|
max_mem_usage = rp->wup->rsc_memory_bound;
|
2004-09-13 05:27:28 +00:00
|
|
|
strcpy(process_control_queue.name, rp->name);
|
|
|
|
strcpy(graphics_request_queue.name, rp->name);
|
2006-06-19 04:29:26 +00:00
|
|
|
get_slot_dir(slot, slot_dir);
|
2003-10-19 02:54:35 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-08-11 11:30:25 +00:00
|
|
|
#if 0
|
|
|
|
// Deallocate memory to prevent unneeded reporting of memory leaks
|
2003-08-12 20:28:55 +00:00
|
|
|
//
|
2004-08-11 11:30:25 +00:00
|
|
|
void ACTIVE_TASK_SET::free_mem() {
|
|
|
|
vector<ACTIVE_TASK*>::iterator at_iter;
|
|
|
|
ACTIVE_TASK *at;
|
2003-08-12 20:28:55 +00:00
|
|
|
|
2004-08-11 11:30:25 +00:00
|
|
|
at_iter = active_tasks.begin();
|
|
|
|
while (at_iter != active_tasks.end()) {
|
|
|
|
at = active_tasks[0];
|
|
|
|
at_iter = active_tasks.erase(at_iter);
|
|
|
|
delete at;
|
2002-04-30 22:22:54 +00:00
|
|
|
}
|
|
|
|
}
|
2004-08-09 19:06:47 +00:00
|
|
|
#endif
|
2002-04-30 22:22:54 +00:00
|
|
|
|
2006-09-05 19:00:59 +00:00
|
|
|
void ACTIVE_TASK_SET::get_memory_usage() {
|
|
|
|
static double last_mem_time=0;
|
2006-11-01 23:36:13 +00:00
|
|
|
unsigned int i;
|
2006-11-01 22:40:30 +00:00
|
|
|
int retval;
|
2006-09-05 19:00:59 +00:00
|
|
|
|
2006-11-01 23:36:13 +00:00
|
|
|
double diff = gstate.now - last_mem_time;
|
2006-09-08 19:27:42 +00:00
|
|
|
if (diff < 10) return;
|
2006-09-05 19:00:59 +00:00
|
|
|
|
|
|
|
last_mem_time = gstate.now;
|
|
|
|
vector<PROCINFO> piv;
|
2006-11-01 22:40:30 +00:00
|
|
|
retval = procinfo_setup(piv);
|
|
|
|
if (retval) {
|
|
|
|
if (log_flags.mem_usage_debug) {
|
|
|
|
msg_printf(0, MSG_ERROR,
|
|
|
|
"[mem_usage_debug] procinfo_setup() returned %d", retval
|
|
|
|
);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
2006-09-05 19:00:59 +00:00
|
|
|
for (i=0; i<active_tasks.size(); i++) {
|
|
|
|
ACTIVE_TASK* atp = active_tasks[i];
|
|
|
|
if (atp->task_state == PROCESS_EXECUTING) {
|
2006-11-01 23:36:13 +00:00
|
|
|
PROCINFO& pi = atp->procinfo;
|
|
|
|
unsigned long last_page_fault_count = pi.page_fault_count;
|
2006-09-05 19:00:59 +00:00
|
|
|
memset(&pi, 0, sizeof(pi));
|
|
|
|
pi.id = atp->pid;
|
|
|
|
procinfo_app(pi, piv);
|
2006-10-03 15:43:38 +00:00
|
|
|
pi.working_set_size_smoothed = .5*pi.working_set_size_smoothed + pi.working_set_size;
|
|
|
|
|
2006-11-01 23:36:13 +00:00
|
|
|
int pf = pi.page_fault_count - last_page_fault_count;
|
|
|
|
pi.page_fault_rate = pf/diff;
|
2006-09-05 19:00:59 +00:00
|
|
|
if (log_flags.mem_usage_debug) {
|
2006-10-03 17:14:56 +00:00
|
|
|
msg_printf(atp->result->project, MSG_INFO,
|
|
|
|
"[mem_usage_debug] %s: RAM %.2fMB, page %.2fMB, %.2f page faults/sec, user CPU %.3f, kernel CPU %.3f",
|
2006-09-05 19:00:59 +00:00
|
|
|
atp->result->name,
|
2006-10-03 17:14:56 +00:00
|
|
|
pi.working_set_size/MEGA, pi.swap_size/MEGA,
|
2006-11-01 23:36:13 +00:00
|
|
|
pi.page_fault_rate,
|
2006-09-05 19:00:59 +00:00
|
|
|
pi.user_time, pi.kernel_time
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
// the following is not useful because most OSs don't
|
|
|
|
// move idle processes out of RAM, so physical memory is always full
|
|
|
|
//
|
|
|
|
procinfo_other(pi, piv);
|
2006-10-03 17:14:56 +00:00
|
|
|
msg_printf(NULL, MSG_INFO, "All others: RAM %.2fMB, page %.2fMB, user %.3f, kernel %.3f",
|
|
|
|
pi.working_set_size/MEGA, pi.swap_size/MEGA,
|
2006-09-05 19:00:59 +00:00
|
|
|
pi.user_time, pi.kernel_time
|
|
|
|
);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2006-02-03 20:48:48 +00:00
|
|
|
// Do periodic checks on running apps:
|
2004-08-11 11:30:25 +00:00
|
|
|
// - 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
|
2004-08-10 20:27:51 +00:00
|
|
|
//
|
2005-06-07 19:22:50 +00:00
|
|
|
bool ACTIVE_TASK_SET::poll() {
|
2004-08-11 11:30:25 +00:00
|
|
|
bool action;
|
2006-11-01 23:36:13 +00:00
|
|
|
unsigned int i;
|
2004-10-14 22:01:05 +00:00
|
|
|
static double last_time = 0;
|
2005-06-07 19:22:50 +00:00
|
|
|
if (gstate.now - last_time < 1.0) return false;
|
|
|
|
last_time = gstate.now;
|
2004-08-10 20:27:51 +00:00
|
|
|
|
2004-08-11 11:30:25 +00:00
|
|
|
action = check_app_exited();
|
|
|
|
send_heartbeats();
|
|
|
|
send_trickle_downs();
|
|
|
|
graphics_poll();
|
2004-09-13 05:27:28 +00:00
|
|
|
process_control_poll();
|
2006-09-05 19:00:59 +00:00
|
|
|
get_memory_usage();
|
2004-08-11 11:30:25 +00:00
|
|
|
action |= check_rsc_limits_exceeded();
|
2006-02-03 20:48:48 +00:00
|
|
|
action |= get_msgs();
|
2006-08-28 18:22:07 +00:00
|
|
|
for (i=0; i<active_tasks.size(); i++) {
|
2006-02-03 20:48:48 +00:00
|
|
|
ACTIVE_TASK* atp = active_tasks[i];
|
|
|
|
if (atp->task_state == PROCESS_ABORT_PENDING) {
|
|
|
|
if (gstate.now > atp->abort_time + 5.0) {
|
|
|
|
atp->kill_task();
|
2006-11-01 23:36:13 +00:00
|
|
|
atp->task_state = PROCESS_ABORTED;
|
2006-02-03 20:48:48 +00:00
|
|
|
}
|
|
|
|
}
|
2002-07-01 18:16:31 +00:00
|
|
|
}
|
2006-02-03 20:48:48 +00:00
|
|
|
|
2004-08-11 11:30:25 +00:00
|
|
|
if (action) {
|
|
|
|
gstate.set_client_state_dirty("ACTIVE_TASK_SET::poll");
|
2003-03-11 22:18:01 +00:00
|
|
|
}
|
2006-08-28 18:22:07 +00:00
|
|
|
|
2004-08-11 11:30:25 +00:00
|
|
|
return action;
|
2002-12-06 07:33:45 +00:00
|
|
|
}
|
2002-06-06 18:42:01 +00:00
|
|
|
|
2002-12-06 07:33:45 +00:00
|
|
|
// Remove an ACTIVE_TASK from the set.
|
2004-02-04 23:18:14 +00:00
|
|
|
// Does NOT delete the ACTIVE_TASK object.
|
2002-07-15 23:21:20 +00:00
|
|
|
//
|
2002-04-30 22:22:54 +00:00
|
|
|
int ACTIVE_TASK_SET::remove(ACTIVE_TASK* atp) {
|
|
|
|
vector<ACTIVE_TASK*>::iterator iter;
|
2002-08-05 00:29:34 +00:00
|
|
|
|
2002-04-30 22:22:54 +00:00
|
|
|
iter = active_tasks.begin();
|
|
|
|
while (iter != active_tasks.end()) {
|
|
|
|
if (*iter == atp) {
|
2006-10-02 17:44:27 +00:00
|
|
|
iter = active_tasks.erase(iter);
|
2002-04-30 22:22:54 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
iter++;
|
|
|
|
}
|
2006-01-17 22:48:09 +00:00
|
|
|
msg_printf(NULL, MSG_ERROR, "Task %s not found", atp->result->name);
|
2004-01-30 22:19:19 +00:00
|
|
|
return ERR_NOT_FOUND;
|
2002-04-30 22:22:54 +00:00
|
|
|
}
|
|
|
|
|
2004-01-04 06:48:40 +00:00
|
|
|
// There's a new trickle file.
|
|
|
|
// Move it from slot dir to project dir
|
|
|
|
//
|
|
|
|
int ACTIVE_TASK::move_trickle_file() {
|
|
|
|
char project_dir[256], new_path[256], old_path[256];
|
|
|
|
int retval;
|
|
|
|
|
|
|
|
get_project_dir(result->project, project_dir);
|
2006-03-03 21:34:03 +00:00
|
|
|
sprintf(old_path, "%s/trickle_up.xml", slot_dir);
|
2004-01-04 06:48:40 +00:00
|
|
|
sprintf(new_path,
|
2006-03-03 21:34:03 +00:00
|
|
|
"%s/trickle_up_%s_%d.xml",
|
|
|
|
project_dir, result->name, (int)time(0)
|
2004-01-04 06:48:40 +00:00
|
|
|
);
|
|
|
|
retval = boinc_rename(old_path, new_path);
|
|
|
|
|
|
|
|
// if can't move it, remove
|
|
|
|
//
|
|
|
|
if (retval) {
|
|
|
|
boinc_delete_file(old_path);
|
|
|
|
return ERR_RENAME;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-06-13 18:23:56 +00:00
|
|
|
// Returns the estimated CPU time to completion (in seconds) of this task.
|
|
|
|
// Compute this as a weighted average of estimates based on
|
|
|
|
// 1) the workunit's flops count
|
|
|
|
// 2) the current reported CPU time and fraction done
|
2002-11-20 20:14:48 +00:00
|
|
|
//
|
2004-10-20 21:11:29 +00:00
|
|
|
double ACTIVE_TASK::est_cpu_time_to_completion() {
|
2005-05-24 00:33:08 +00:00
|
|
|
if (fraction_done >= 1) return 0;
|
2005-06-13 18:23:56 +00:00
|
|
|
double wu_est = result->estimated_cpu_time();
|
|
|
|
if (fraction_done <= 0) return wu_est;
|
|
|
|
double frac_est = (current_cpu_time / fraction_done) - current_cpu_time;
|
2005-11-02 22:06:54 +00:00
|
|
|
double fraction_left = 1-fraction_done;
|
|
|
|
return fraction_done*frac_est + fraction_left*fraction_left*wu_est;
|
2002-11-20 20:14:48 +00:00
|
|
|
}
|
|
|
|
|
2002-12-06 07:33:45 +00:00
|
|
|
// size of output files and files in slot dir
|
|
|
|
//
|
|
|
|
int ACTIVE_TASK::current_disk_usage(double& size) {
|
|
|
|
double x;
|
|
|
|
unsigned int i;
|
|
|
|
int retval;
|
|
|
|
FILE_INFO* fip;
|
|
|
|
char path[256];
|
|
|
|
|
|
|
|
retval = dir_size(slot_dir, size);
|
|
|
|
if (retval) return retval;
|
|
|
|
for (i=0; i<result->output_files.size(); i++) {
|
|
|
|
fip = result->output_files[i].file_info;
|
|
|
|
get_pathname(fip, path);
|
|
|
|
retval = file_size(path, x);
|
|
|
|
if (!retval) size += x;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-06-30 01:10:22 +00:00
|
|
|
// Get the next free slot
|
2002-08-26 22:14:06 +00:00
|
|
|
//
|
2004-06-30 01:10:22 +00:00
|
|
|
int ACTIVE_TASK_SET::get_free_slot() {
|
2002-09-22 23:27:14 +00:00
|
|
|
unsigned int i;
|
2003-02-24 21:25:16 +00:00
|
|
|
int j;
|
|
|
|
bool found;
|
2002-08-26 22:14:06 +00:00
|
|
|
|
2004-06-30 01:10:22 +00:00
|
|
|
for (j=0; ; j++) {
|
2003-02-24 21:25:16 +00:00
|
|
|
found = false;
|
|
|
|
for (i=0; i<active_tasks.size(); i++) {
|
|
|
|
if (active_tasks[i]->slot == j) {
|
|
|
|
found = true;
|
|
|
|
break;
|
|
|
|
}
|
2002-08-26 22:14:06 +00:00
|
|
|
}
|
2003-02-24 21:25:16 +00:00
|
|
|
if (!found) return j;
|
2002-08-26 22:14:06 +00:00
|
|
|
}
|
2005-04-28 23:19:58 +00:00
|
|
|
return ERR_NOT_FOUND; // probably never get here
|
2002-08-26 22:14:06 +00:00
|
|
|
}
|
|
|
|
|
2006-06-15 05:14:39 +00:00
|
|
|
bool ACTIVE_TASK_SET::slot_taken(int slot) {
|
|
|
|
unsigned int i;
|
|
|
|
for (i=0; i<active_tasks.size(); i++) {
|
|
|
|
if (active_tasks[i]->slot == slot) return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2004-06-12 04:45:36 +00:00
|
|
|
int ACTIVE_TASK::write(MIOFILE& fout) {
|
|
|
|
fout.printf(
|
2002-04-30 22:22:54 +00:00
|
|
|
"<active_task>\n"
|
2002-06-21 06:52:47 +00:00
|
|
|
" <project_master_url>%s</project_master_url>\n"
|
2002-04-30 22:22:54 +00:00
|
|
|
" <result_name>%s</result_name>\n"
|
2004-10-26 20:53:24 +00:00
|
|
|
" <active_task_state>%d</active_task_state>\n"
|
2002-04-30 22:22:54 +00:00
|
|
|
" <app_version_num>%d</app_version_num>\n"
|
|
|
|
" <slot>%d</slot>\n"
|
2004-06-30 01:10:22 +00:00
|
|
|
" <scheduler_state>%d</scheduler_state>\n"
|
2002-08-05 00:29:34 +00:00
|
|
|
" <checkpoint_cpu_time>%f</checkpoint_cpu_time>\n"
|
2004-01-22 19:30:42 +00:00
|
|
|
" <fraction_done>%f</fraction_done>\n"
|
|
|
|
" <current_cpu_time>%f</current_cpu_time>\n"
|
2006-09-08 19:27:42 +00:00
|
|
|
" <swap_size>%f</swap_size>\n"
|
|
|
|
" <working_set_size>%f</working_set_size>\n"
|
2006-10-03 17:24:25 +00:00
|
|
|
" <working_set_size_smoothed>%f</working_set_size_smoothed>\n"
|
2006-11-01 23:36:13 +00:00
|
|
|
" <page_fault_rate>%f</page_fault_rate>\n"
|
2006-10-03 22:50:13 +00:00
|
|
|
"%s",
|
2002-06-21 06:52:47 +00:00
|
|
|
result->project->master_url,
|
2002-04-30 22:22:54 +00:00
|
|
|
result->name,
|
2005-01-21 23:26:36 +00:00
|
|
|
task_state,
|
2002-04-30 22:22:54 +00:00
|
|
|
app_version->version_num,
|
|
|
|
slot,
|
2004-06-30 01:10:22 +00:00
|
|
|
scheduler_state,
|
2004-01-22 19:30:42 +00:00
|
|
|
checkpoint_cpu_time,
|
|
|
|
fraction_done,
|
2004-10-21 00:23:19 +00:00
|
|
|
current_cpu_time,
|
2006-09-08 19:27:42 +00:00
|
|
|
procinfo.swap_size,
|
|
|
|
procinfo.working_set_size,
|
2006-10-03 17:24:25 +00:00
|
|
|
procinfo.working_set_size_smoothed,
|
2006-11-01 23:36:13 +00:00
|
|
|
procinfo.page_fault_rate,
|
2006-10-03 22:50:13 +00:00
|
|
|
too_large?" <too_large/>\n":""
|
2002-04-30 22:22:54 +00:00
|
|
|
);
|
2006-03-16 20:29:44 +00:00
|
|
|
if (supports_graphics() && !gstate.disable_graphics) {
|
2005-04-21 23:53:39 +00:00
|
|
|
fout.printf(
|
|
|
|
" <supports_graphics/>\n"
|
|
|
|
" <graphics_mode_acked>%d</graphics_mode_acked>\n",
|
|
|
|
graphics_mode_acked
|
|
|
|
);
|
|
|
|
}
|
|
|
|
fout.printf("</active_task>\n");
|
2002-04-30 22:22:54 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-06-12 04:45:36 +00:00
|
|
|
int ACTIVE_TASK::parse(MIOFILE& fin) {
|
2002-06-21 06:52:47 +00:00
|
|
|
char buf[256], result_name[256], project_master_url[256];
|
2005-05-12 22:44:45 +00:00
|
|
|
int app_version_num=0, n;
|
2005-08-12 00:10:54 +00:00
|
|
|
unsigned int i;
|
2002-04-30 22:22:54 +00:00
|
|
|
PROJECT* project;
|
2002-08-05 00:29:34 +00:00
|
|
|
|
2003-03-19 01:15:46 +00:00
|
|
|
strcpy(result_name, "");
|
|
|
|
strcpy(project_master_url, "");
|
2004-07-08 17:59:46 +00:00
|
|
|
|
2004-06-12 04:45:36 +00:00
|
|
|
while (fin.fgets(buf, 256)) {
|
2002-04-30 22:22:54 +00:00
|
|
|
if (match_tag(buf, "</active_task>")) {
|
2004-06-12 04:45:36 +00:00
|
|
|
project = gstate.lookup_project(project_master_url);
|
2002-04-30 22:22:54 +00:00
|
|
|
if (!project) {
|
2003-07-03 05:01:29 +00:00
|
|
|
msg_printf(
|
|
|
|
NULL, MSG_ERROR,
|
2006-01-17 22:48:09 +00:00
|
|
|
"State file error: project %s not found\n",
|
2002-06-21 06:52:47 +00:00
|
|
|
project_master_url
|
2002-04-30 22:22:54 +00:00
|
|
|
);
|
2003-10-21 04:06:55 +00:00
|
|
|
return ERR_NULL;
|
2002-04-30 22:22:54 +00:00
|
|
|
}
|
2004-06-12 04:45:36 +00:00
|
|
|
result = gstate.lookup_result(project, result_name);
|
2002-04-30 22:22:54 +00:00
|
|
|
if (!result) {
|
2003-07-03 05:01:29 +00:00
|
|
|
msg_printf(
|
2006-01-17 22:48:09 +00:00
|
|
|
project, MSG_ERROR,
|
|
|
|
"State file error: result %s not found\n",
|
|
|
|
result_name
|
2003-07-03 05:01:29 +00:00
|
|
|
);
|
2003-10-21 04:06:55 +00:00
|
|
|
return ERR_NULL;
|
2002-04-30 22:22:54 +00:00
|
|
|
}
|
2003-11-06 00:00:00 +00:00
|
|
|
|
|
|
|
// various sanity checks
|
|
|
|
//
|
|
|
|
if (result->got_server_ack
|
|
|
|
|| result->ready_to_report
|
|
|
|
|| result->state != RESULT_FILES_DOWNLOADED
|
|
|
|
) {
|
|
|
|
msg_printf(project, MSG_ERROR,
|
2006-01-17 22:48:09 +00:00
|
|
|
"State file error: result %s is in wrong state\n",
|
|
|
|
result_name
|
2003-11-06 00:00:00 +00:00
|
|
|
);
|
|
|
|
return ERR_BAD_RESULT_STATE;
|
|
|
|
}
|
|
|
|
|
2002-04-30 22:22:54 +00:00
|
|
|
wup = result->wup;
|
2004-06-12 04:45:36 +00:00
|
|
|
app_version = gstate.lookup_app_version(
|
2002-04-30 22:22:54 +00:00
|
|
|
result->app, app_version_num
|
|
|
|
);
|
|
|
|
if (!app_version) {
|
2003-07-03 05:01:29 +00:00
|
|
|
msg_printf(
|
2003-11-06 00:00:00 +00:00
|
|
|
project, MSG_ERROR,
|
2006-01-17 22:48:09 +00:00
|
|
|
"State file error: application %s version %d not found\n",
|
|
|
|
result->app->name, app_version_num
|
2003-07-03 05:01:29 +00:00
|
|
|
);
|
2003-11-06 00:00:00 +00:00
|
|
|
return ERR_NULL;
|
2002-04-30 22:22:54 +00:00
|
|
|
}
|
2005-08-12 00:10:54 +00:00
|
|
|
|
|
|
|
// make sure no two active tasks are in same slot
|
|
|
|
//
|
|
|
|
for (i=0; i<gstate.active_tasks.active_tasks.size(); i++) {
|
|
|
|
ACTIVE_TASK* atp = gstate.active_tasks.active_tasks[i];
|
|
|
|
if (atp->slot == slot) {
|
|
|
|
msg_printf(project, MSG_ERROR,
|
2006-01-17 22:48:09 +00:00
|
|
|
"State file error: two tasks in slot %d\n", slot
|
2005-08-12 00:10:54 +00:00
|
|
|
);
|
|
|
|
return ERR_BAD_RESULT_STATE;
|
|
|
|
}
|
|
|
|
}
|
2002-04-30 22:22:54 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2002-09-22 23:27:14 +00:00
|
|
|
else if (parse_str(buf, "<result_name>", result_name, sizeof(result_name))) continue;
|
|
|
|
else if (parse_str(buf, "<project_master_url>", project_master_url, sizeof(project_master_url))) continue;
|
2002-04-30 22:22:54 +00:00
|
|
|
else if (parse_int(buf, "<app_version_num>", app_version_num)) continue;
|
|
|
|
else if (parse_int(buf, "<slot>", slot)) continue;
|
2002-08-24 00:41:25 +00:00
|
|
|
else if (parse_double(buf, "<checkpoint_cpu_time>", checkpoint_cpu_time)) continue;
|
2004-01-22 19:30:42 +00:00
|
|
|
else if (parse_double(buf, "<fraction_done>", fraction_done)) continue;
|
|
|
|
else if (parse_double(buf, "<current_cpu_time>", current_cpu_time)) continue;
|
2005-05-12 22:44:45 +00:00
|
|
|
else if (parse_int(buf, "<active_task_state>", n)) continue;
|
2006-09-08 19:27:42 +00:00
|
|
|
else if (parse_double(buf, "<swap_size>", procinfo.swap_size)) continue;
|
|
|
|
else if (parse_double(buf, "<working_set_size>", procinfo.working_set_size)) continue;
|
2006-10-03 17:24:25 +00:00
|
|
|
else if (parse_double(buf, "<working_set_size_smoothed>", procinfo.working_set_size_smoothed)) continue;
|
2006-09-08 19:27:42 +00:00
|
|
|
else if (parse_double(buf, "<page_fault_rate>", procinfo.page_fault_rate)) continue;
|
2005-05-20 20:50:45 +00:00
|
|
|
else if (match_tag(buf, "<supports_graphics/>")) continue;
|
|
|
|
else if (parse_int(buf, "<graphics_mode_acked>", n)) continue;
|
2006-07-11 22:52:17 +00:00
|
|
|
else if (parse_int(buf, "<scheduler_state>", n)) continue;
|
2006-06-22 19:40:30 +00:00
|
|
|
else {
|
|
|
|
if (log_flags.unparsed_xml) {
|
|
|
|
msg_printf(0, MSG_ERROR,
|
2006-09-07 20:39:25 +00:00
|
|
|
"[unparsed_xml] ACTIVE_TASK::parse(): unrecognized %s\n", buf
|
2006-06-22 19:40:30 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
2002-04-30 22:22:54 +00:00
|
|
|
}
|
2003-10-21 04:06:55 +00:00
|
|
|
return ERR_XML_PARSE;
|
2002-04-30 22:22:54 +00:00
|
|
|
}
|
|
|
|
|
2002-07-15 23:21:20 +00:00
|
|
|
// Write XML information about this active task set
|
|
|
|
//
|
2004-06-12 04:45:36 +00:00
|
|
|
int ACTIVE_TASK_SET::write(MIOFILE& fout) {
|
2002-04-30 22:22:54 +00:00
|
|
|
unsigned int i;
|
2003-03-08 23:48:05 +00:00
|
|
|
int retval;
|
2002-08-05 00:29:34 +00:00
|
|
|
|
2004-06-12 04:45:36 +00:00
|
|
|
fout.printf("<active_task_set>\n");
|
2002-04-30 22:22:54 +00:00
|
|
|
for (i=0; i<active_tasks.size(); i++) {
|
2003-03-08 23:48:05 +00:00
|
|
|
retval = active_tasks[i]->write(fout);
|
|
|
|
if (retval) return retval;
|
2002-04-30 22:22:54 +00:00
|
|
|
}
|
2004-06-12 04:45:36 +00:00
|
|
|
fout.printf("</active_task_set>\n");
|
2002-04-30 22:22:54 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2002-07-15 23:21:20 +00:00
|
|
|
// Parse XML information about an active task set
|
|
|
|
//
|
2004-06-12 04:45:36 +00:00
|
|
|
int ACTIVE_TASK_SET::parse(MIOFILE& fin) {
|
2002-04-30 22:22:54 +00:00
|
|
|
ACTIVE_TASK* atp;
|
|
|
|
char buf[256];
|
|
|
|
int retval;
|
2002-08-05 00:29:34 +00:00
|
|
|
|
2004-06-12 04:45:36 +00:00
|
|
|
while (fin.fgets(buf, 256)) {
|
2002-04-30 22:22:54 +00:00
|
|
|
if (match_tag(buf, "</active_task_set>")) return 0;
|
|
|
|
else if (match_tag(buf, "<active_task>")) {
|
|
|
|
atp = new ACTIVE_TASK;
|
2004-06-12 04:45:36 +00:00
|
|
|
retval = atp->parse(fin);
|
2006-06-15 05:14:39 +00:00
|
|
|
if (!retval) {
|
|
|
|
if (slot_taken(atp->slot)) {
|
|
|
|
msg_printf(atp->result->project, MSG_ERROR,
|
|
|
|
"slot %d in use; discarding result %s",
|
|
|
|
atp->slot, atp->result->name
|
|
|
|
);
|
|
|
|
retval = ERR_XML_PARSE;
|
|
|
|
}
|
|
|
|
}
|
2002-04-30 22:22:54 +00:00
|
|
|
if (!retval) active_tasks.push_back(atp);
|
|
|
|
else delete atp;
|
2006-06-22 19:40:30 +00:00
|
|
|
} else {
|
|
|
|
if (log_flags.unparsed_xml) {
|
|
|
|
msg_printf(0, MSG_ERROR,
|
2006-09-07 20:39:25 +00:00
|
|
|
"[unparsed_xml] ACTIVE_TASK_SET::parse(): unrecognized %s\n", buf
|
2006-06-22 19:40:30 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
2002-04-30 22:22:54 +00:00
|
|
|
}
|
2005-10-10 03:21:52 +00:00
|
|
|
return ERR_XML_PARSE;
|
2002-04-30 22:22:54 +00:00
|
|
|
}
|
2004-09-13 05:27:28 +00:00
|
|
|
|
2005-02-16 23:17:43 +00:00
|
|
|
void MSG_QUEUE::msg_queue_send(const char* msg, MSG_CHANNEL& channel) {
|
2004-09-13 05:27:28 +00:00
|
|
|
if (channel.send_msg(msg)) {
|
|
|
|
//msg_printf(NULL, MSG_INFO, "sent %s to %s", msg, name);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
msgs.push_back(std::string(msg));
|
|
|
|
}
|
|
|
|
|
|
|
|
void MSG_QUEUE::msg_queue_poll(MSG_CHANNEL& channel) {
|
|
|
|
if (msgs.size() > 0) {
|
2005-02-16 23:17:43 +00:00
|
|
|
if (channel.send_msg(msgs[0].c_str())) {
|
|
|
|
//msg_printf(NULL, MSG_INFO, "sent %s to %s (delayed)", (msgs[0].c_str()), name);
|
2004-09-13 05:27:28 +00:00
|
|
|
msgs.erase(msgs.begin());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2004-12-08 00:40:19 +00:00
|
|
|
|
2005-06-07 19:22:50 +00:00
|
|
|
void ACTIVE_TASK_SET::report_overdue() {
|
2005-04-20 06:16:54 +00:00
|
|
|
unsigned int i;
|
|
|
|
ACTIVE_TASK* atp;
|
|
|
|
|
|
|
|
for (i=0; i<active_tasks.size(); i++) {
|
|
|
|
atp = active_tasks[i];
|
2005-06-07 19:22:50 +00:00
|
|
|
double diff = (gstate.now - atp->result->report_deadline)/86400;
|
2005-04-20 06:16:54 +00:00
|
|
|
if (diff > 0) {
|
|
|
|
msg_printf(atp->result->project, MSG_ERROR,
|
2006-01-17 22:48:09 +00:00
|
|
|
"Task %s is %.2f days overdue.", atp->result->name, diff
|
2005-04-20 06:16:54 +00:00
|
|
|
);
|
|
|
|
msg_printf(atp->result->project, MSG_ERROR,
|
|
|
|
"You may not get credit for it. Consider aborting it."
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-04-28 23:19:58 +00:00
|
|
|
// scan the slot directory, looking for files with names
|
|
|
|
// of the form boinc_ufr_X.
|
|
|
|
// Then mark file X as being present (and uploadable)
|
|
|
|
//
|
|
|
|
int ACTIVE_TASK::handle_upload_files() {
|
|
|
|
std::string filename;
|
|
|
|
char buf[256], path[256];
|
2005-05-02 20:32:36 +00:00
|
|
|
int retval;
|
2005-04-28 23:19:58 +00:00
|
|
|
|
|
|
|
DirScanner dirscan(slot_dir);
|
|
|
|
while (dirscan.scan(filename)) {
|
|
|
|
strcpy(buf, filename.c_str());
|
|
|
|
if (strstr(buf, UPLOAD_FILE_REQ_PREFIX) == buf) {
|
|
|
|
char* p = buf+strlen(UPLOAD_FILE_REQ_PREFIX);
|
|
|
|
FILE_INFO* fip = result->lookup_file_logical(p);
|
|
|
|
if (fip) {
|
2005-05-02 20:32:36 +00:00
|
|
|
get_pathname(fip, path);
|
2005-06-08 19:02:27 +00:00
|
|
|
retval = md5_file(path, fip->md5_cksum, fip->nbytes);
|
2005-05-02 20:32:36 +00:00
|
|
|
if (retval) {
|
|
|
|
fip->status = retval;
|
|
|
|
} else {
|
|
|
|
fip->status = FILE_PRESENT;
|
|
|
|
}
|
2005-04-28 23:19:58 +00:00
|
|
|
} else {
|
2006-01-17 22:48:09 +00:00
|
|
|
msg_printf(0, MSG_ERROR, "Can't find uploadable file %s", p);
|
2005-04-28 23:19:58 +00:00
|
|
|
}
|
|
|
|
sprintf(path, "%s/%s", slot_dir, buf);
|
|
|
|
boinc_delete_file(path);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ACTIVE_TASK_SET::handle_upload_files() {
|
|
|
|
for (unsigned int i=0; i<active_tasks.size(); i++) {
|
|
|
|
ACTIVE_TASK* atp = active_tasks[i];
|
|
|
|
atp->handle_upload_files();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-08-17 22:08:35 +00:00
|
|
|
bool ACTIVE_TASK_SET::want_network() {
|
|
|
|
for (unsigned int i=0; i<active_tasks.size(); i++) {
|
|
|
|
ACTIVE_TASK* atp = active_tasks[i];
|
|
|
|
if (atp->want_network) return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ACTIVE_TASK_SET::network_available() {
|
|
|
|
for (unsigned int i=0; i<active_tasks.size(); i++) {
|
|
|
|
ACTIVE_TASK* atp = active_tasks[i];
|
|
|
|
if (atp->want_network) {
|
|
|
|
atp->send_network_available();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-04-28 23:19:58 +00:00
|
|
|
void ACTIVE_TASK::upload_notify_app(const FILE_INFO* fip, const FILE_REF* frp) {
|
|
|
|
char path[256];
|
|
|
|
sprintf(path, "%s/%s%s", slot_dir, UPLOAD_FILE_STATUS_PREFIX, frp->open_name);
|
|
|
|
FILE* f = boinc_fopen(path, "w");
|
|
|
|
if (!f) return;
|
|
|
|
fprintf(f, "<status>%d</status>\n", fip->status);
|
|
|
|
fclose(f);
|
|
|
|
send_upload_file_status = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// a file upload has finished.
|
|
|
|
// If any running apps are waiting for it, notify them
|
|
|
|
//
|
|
|
|
void ACTIVE_TASK_SET::upload_notify_app(FILE_INFO* fip) {
|
|
|
|
for (unsigned int i=0; i<active_tasks.size(); i++) {
|
|
|
|
ACTIVE_TASK* atp = active_tasks[i];
|
|
|
|
RESULT* rp = atp->result;
|
|
|
|
FILE_REF* frp = rp->lookup_file(fip);
|
|
|
|
if (frp) {
|
|
|
|
atp->upload_notify_app(fip, frp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-06-19 04:29:26 +00:00
|
|
|
void ACTIVE_TASK_SET::init() {
|
|
|
|
for (unsigned int i=0; i<active_tasks.size(); i++) {
|
|
|
|
ACTIVE_TASK* atp = active_tasks[i];
|
|
|
|
atp->init(atp->result);
|
|
|
|
atp->scheduler_state = CPU_SCHED_PREEMPTED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-01-02 18:29:53 +00:00
|
|
|
const char *BOINC_RCSID_778b61195e = "$Id$";
|