2003-07-01 20:37:09 +00:00
|
|
|
// The contents of this file are subject to the BOINC Public License
|
2002-04-30 22:22:54 +00:00
|
|
|
// Version 1.0 (the "License"); you may not use this file except in
|
|
|
|
// compliance with the License. You may obtain a copy of the License at
|
2003-07-01 20:37:09 +00:00
|
|
|
// http://boinc.berkeley.edu/license_1.0.txt
|
2003-07-02 02:02:18 +00:00
|
|
|
//
|
2002-04-30 22:22:54 +00:00
|
|
|
// Software distributed under the License is distributed on an "AS IS"
|
|
|
|
// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
|
|
|
// License for the specific language governing rights and limitations
|
2003-07-02 02:02:18 +00:00
|
|
|
// under the License.
|
|
|
|
//
|
|
|
|
// The Original Code is the Berkeley Open Infrastructure for Network Computing.
|
|
|
|
//
|
2002-04-30 22:22:54 +00:00
|
|
|
// The Initial Developer of the Original Code is the SETI@home project.
|
2003-07-02 20:57:59 +00:00
|
|
|
// Portions created by the SETI@home project are Copyright (C) 2002
|
2003-07-02 02:02:18 +00:00
|
|
|
// University of California at Berkeley. All Rights Reserved.
|
|
|
|
//
|
2002-04-30 22:22:54 +00:00
|
|
|
// Contributor(s):
|
|
|
|
//
|
|
|
|
|
|
|
|
// 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"
|
2002-07-05 19:20:00 +00:00
|
|
|
#endif
|
2004-03-04 11:41:43 +00:00
|
|
|
|
|
|
|
#ifndef _WIN32
|
|
|
|
|
2004-07-13 13:54:09 +00:00
|
|
|
#include <cerrno>
|
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_SYS_SIGNAL_H
|
2002-07-01 18:16:31 +00:00
|
|
|
#include <sys/signal.h>
|
2002-07-05 19:20:00 +00:00
|
|
|
#endif
|
2003-03-20 19:16:28 +00:00
|
|
|
#if HAVE_SYS_IPC_H
|
|
|
|
#include <sys/ipc.h>
|
|
|
|
#endif
|
2002-07-05 19:20:00 +00:00
|
|
|
#if HAVE_FCNTL_H
|
2002-04-30 22:22:54 +00:00
|
|
|
#include <fcntl.h>
|
2002-07-05 19:20:00 +00:00
|
|
|
#endif
|
2004-07-13 13:54:09 +00:00
|
|
|
#include <csignal>
|
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-07-08 17:59:46 +00:00
|
|
|
#include "app_ipc.h"
|
2002-04-30 22:22:54 +00:00
|
|
|
|
2004-04-08 08:15:23 +00:00
|
|
|
#include "client_msgs.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::vector;
|
|
|
|
using std::max;
|
2004-07-02 03:20:17 +00:00
|
|
|
using std::min;
|
2004-06-30 18:17:21 +00:00
|
|
|
|
2004-08-06 23:17:59 +00:00
|
|
|
// ways an active task can be started by the client
|
2004-07-29 17:18:36 +00:00
|
|
|
//
|
2004-08-06 23:17:59 +00:00
|
|
|
#define TASK_RESUME 0 // process suspended; call unsuspend()
|
|
|
|
#define TASK_RESTART 1 // process uninitalized; call start(false)
|
|
|
|
#define TASK_START 2 // process uninitalized; call start(true)
|
2004-06-30 18:17:21 +00:00
|
|
|
|
2003-08-11 03:33:14 +00:00
|
|
|
// value for setpriority(2)
|
|
|
|
static const int PROCESS_IDLE_PRIORITY = 19;
|
|
|
|
|
2002-07-15 23:21:20 +00:00
|
|
|
// Goes through an array of strings, and prints each string
|
|
|
|
//
|
2003-07-02 02:02:18 +00:00
|
|
|
static int debug_print_argv(char** argv) {
|
2002-04-30 22:22:54 +00:00
|
|
|
int i;
|
2002-07-15 23:21:20 +00:00
|
|
|
|
2004-04-08 08:15:23 +00:00
|
|
|
log_messages.printf(CLIENT_MSG_LOG::DEBUG_TASK, "Arguments:");
|
2003-07-02 02:02:18 +00:00
|
|
|
++log_messages;
|
2002-04-30 22:22:54 +00:00
|
|
|
for (i=0; argv[i]; i++) {
|
2003-11-07 23:26:17 +00:00
|
|
|
log_messages.printf(
|
2004-04-08 08:15:23 +00:00
|
|
|
CLIENT_MSG_LOG::DEBUG_TASK,
|
2003-11-07 23:26:17 +00:00
|
|
|
"argv[%d]: %s\n", i, argv[i]
|
|
|
|
);
|
2002-04-30 22:22:54 +00:00
|
|
|
}
|
2003-07-02 02:02:18 +00:00
|
|
|
--log_messages;
|
2002-07-15 23:21:20 +00:00
|
|
|
|
|
|
|
return 0;
|
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;
|
2002-07-15 23:21:20 +00:00
|
|
|
state = PROCESS_UNINITIALIZED;
|
2004-06-30 01:10:22 +00:00
|
|
|
scheduler_state = CPU_SCHED_UNINITIALIZED;
|
2002-04-30 22:22:54 +00:00
|
|
|
exit_status = 0;
|
|
|
|
signal = 0;
|
2003-03-19 01:15:46 +00:00
|
|
|
strcpy(slot_dir, "");
|
2004-07-18 04:41:27 +00:00
|
|
|
graphics_mode_requested = MODE_HIDE_GRAPHICS;
|
|
|
|
graphics_mode_sent = 0;
|
|
|
|
graphics_mode_acked = MODE_UNSUPPORTED;
|
2003-05-09 20:33:57 +00:00
|
|
|
graphics_mode_before_ss = MODE_HIDE_GRAPHICS;
|
2003-08-13 20:00:19 +00:00
|
|
|
|
2004-04-03 01:26:40 +00:00
|
|
|
fraction_done = 0;
|
|
|
|
frac_rate_of_change = 0;
|
|
|
|
last_frac_done = 0;
|
|
|
|
recent_change = 0;
|
|
|
|
last_frac_update = 0;
|
2004-05-21 20:06:34 +00:00
|
|
|
episode_start_cpu_time = 0;
|
2004-06-30 01:10:22 +00:00
|
|
|
cpu_time_at_last_sched = 0;
|
2004-04-03 01:26:40 +00:00
|
|
|
checkpoint_cpu_time = 0;
|
|
|
|
current_cpu_time = 0;
|
2004-07-26 22:23:16 +00:00
|
|
|
vm_size = 0;
|
|
|
|
resident_set_size = 0;
|
2004-07-02 04:49:17 +00:00
|
|
|
have_trickle_down = false;
|
2004-08-06 23:17:59 +00:00
|
|
|
pending_suspend_via_quit = false;
|
2004-02-04 23:18:14 +00:00
|
|
|
#ifdef _WIN32
|
2004-04-03 01:26:40 +00:00
|
|
|
pid_handle = 0;
|
|
|
|
thread_handle = 0;
|
|
|
|
quitRequestEvent = 0;
|
|
|
|
shm_handle = 0;
|
2004-02-04 23:18:14 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
ACTIVE_TASK::~ACTIVE_TASK() {
|
|
|
|
#ifdef _WIN32
|
2004-04-03 01:26:40 +00:00
|
|
|
if (pid_handle) CloseHandle(pid_handle);
|
|
|
|
if (thread_handle) CloseHandle(thread_handle);
|
|
|
|
if (quitRequestEvent) CloseHandle(quitRequestEvent);
|
2004-02-04 23:18:14 +00:00
|
|
|
// detach from shared mem.
|
2004-04-03 01:26:40 +00:00
|
|
|
// This will destroy shmem seg since we're the last attachment
|
2004-02-04 23:18:14 +00:00
|
|
|
//
|
|
|
|
if (app_client_shm.shm) {
|
|
|
|
detach_shmem(shm_handle, app_client_shm.shm);
|
|
|
|
app_client_shm.shm = NULL;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
// detach from and destroy share mem
|
|
|
|
//
|
2004-02-05 05:51:30 +00:00
|
|
|
if (app_client_shm.shm) {
|
|
|
|
detach_shmem(app_client_shm.shm);
|
|
|
|
app_client_shm.shm = NULL;
|
2004-02-04 23:18:14 +00:00
|
|
|
}
|
2004-02-05 05:51:30 +00:00
|
|
|
destroy_shmem(shm_key);
|
2004-02-04 23:18:14 +00:00
|
|
|
#endif
|
2002-04-30 22:22:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int ACTIVE_TASK::init(RESULT* rp) {
|
|
|
|
result = rp;
|
|
|
|
wup = rp->wup;
|
|
|
|
app_version = wup->avp;
|
2003-09-08 06:01:41 +00:00
|
|
|
max_cpu_time = rp->wup->rsc_fpops_bound/gstate.host_info.p_fpops;
|
2003-09-04 00:41:51 +00:00
|
|
|
max_disk_usage = rp->wup->rsc_disk_bound;
|
|
|
|
max_mem_usage = rp->wup->rsc_memory_bound;
|
2003-07-02 02:02:18 +00:00
|
|
|
|
2002-04-30 22:22:54 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2003-11-02 22:51:49 +00:00
|
|
|
int ACTIVE_TASK::link_user_files() {
|
|
|
|
PROJECT* project = wup->project;
|
|
|
|
unsigned int i;
|
|
|
|
FILE_REF fref;
|
|
|
|
FILE_INFO* fip;
|
|
|
|
char link_path[256], buf[256], file_path[256];
|
|
|
|
int retval;
|
|
|
|
|
|
|
|
for (i=0; i<project->user_files.size(); i++) {
|
|
|
|
fref = project->user_files[i];
|
|
|
|
fip = fref.file_info;
|
|
|
|
if (fip->status != FILE_PRESENT) continue;
|
|
|
|
get_pathname(fip, file_path);
|
|
|
|
sprintf(link_path, "%s%s%s", slot_dir, PATH_SEPARATOR, strlen(fref.open_name)?fref.open_name:fip->name);
|
|
|
|
sprintf(buf, "..%s..%s%s", PATH_SEPARATOR, PATH_SEPARATOR, file_path);
|
|
|
|
retval = boinc_link(buf, link_path);
|
|
|
|
if (retval) return retval;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-05-21 20:06:34 +00:00
|
|
|
// write the app init file.
|
|
|
|
// This is done before starting the app,
|
|
|
|
// and when project prefs have changed during app execution
|
|
|
|
//
|
2003-10-31 22:37:46 +00:00
|
|
|
int ACTIVE_TASK::write_app_init_file(APP_INIT_DATA& aid) {
|
2002-08-24 00:41:25 +00:00
|
|
|
FILE *f;
|
2004-04-23 00:05:16 +00:00
|
|
|
char init_data_path[256], project_dir[256], project_path[256];
|
2003-10-31 22:37:46 +00:00
|
|
|
int retval;
|
2002-08-05 00:29:34 +00:00
|
|
|
|
|
|
|
memset(&aid, 0, sizeof(aid));
|
2002-08-22 20:19:18 +00:00
|
|
|
|
2004-08-03 09:50:24 +00:00
|
|
|
aid.core_version = gstate.core_client_major_version*100 + gstate.core_client_minor_version;
|
2003-09-27 17:53:43 +00:00
|
|
|
safe_strcpy(aid.app_name, wup->app->name);
|
2003-04-03 18:35:40 +00:00
|
|
|
safe_strcpy(aid.user_name, wup->project->user_name);
|
|
|
|
safe_strcpy(aid.team_name, wup->project->team_name);
|
2003-11-28 19:19:11 +00:00
|
|
|
if (wup->project->project_specific_prefs.length()) {
|
2004-04-23 23:01:04 +00:00
|
|
|
strcpy(aid.project_preferences, wup->project->project_specific_prefs.c_str());
|
2003-02-24 21:25:16 +00:00
|
|
|
}
|
2004-04-23 00:05:16 +00:00
|
|
|
get_project_dir(wup->project, project_dir);
|
|
|
|
relative_to_absolute(project_dir, project_path);
|
|
|
|
strcpy(aid.project_dir, project_path);
|
2004-04-23 22:51:28 +00:00
|
|
|
relative_to_absolute("", aid.boinc_dir);
|
|
|
|
strcpy(aid.authenticator, wup->project->authenticator);
|
|
|
|
aid.slot = slot;
|
2004-04-23 00:05:16 +00:00
|
|
|
strcpy(aid.wu_name, wup->name);
|
2003-02-24 21:25:16 +00:00
|
|
|
aid.user_total_credit = wup->project->user_total_credit;
|
|
|
|
aid.user_expavg_credit = wup->project->user_expavg_credit;
|
|
|
|
aid.host_total_credit = wup->project->host_total_credit;
|
|
|
|
aid.host_expavg_credit = wup->project->host_expavg_credit;
|
2003-03-20 02:05:25 +00:00
|
|
|
aid.checkpoint_period = gstate.global_prefs.disk_interval;
|
2002-08-05 00:29:34 +00:00
|
|
|
aid.fraction_done_update_period = DEFAULT_FRACTION_DONE_UPDATE_PERIOD;
|
2004-05-24 04:03:34 +00:00
|
|
|
aid.fraction_done_start = 0;
|
|
|
|
aid.fraction_done_end = 1;
|
2004-03-26 20:32:39 +00:00
|
|
|
#ifndef _WIN32
|
2003-03-17 19:24:38 +00:00
|
|
|
aid.shm_key = 0;
|
2004-03-26 20:32:39 +00:00
|
|
|
#endif
|
2004-05-21 20:06:34 +00:00
|
|
|
// wu_cpu_time is the CPU time at start of session,
|
|
|
|
// not the checkpoint CPU time
|
|
|
|
// At the start of an episode these are equal, but not in the middle!
|
|
|
|
//
|
|
|
|
aid.wu_cpu_time = episode_start_cpu_time;
|
2002-08-05 00:29:34 +00:00
|
|
|
|
2002-08-24 00:41:25 +00:00
|
|
|
sprintf(init_data_path, "%s%s%s", slot_dir, PATH_SEPARATOR, INIT_DATA_FILE);
|
2003-12-24 00:50:51 +00:00
|
|
|
f = boinc_fopen(init_data_path, "w");
|
2002-08-24 00:41:25 +00:00
|
|
|
if (!f) {
|
2003-10-02 18:51:38 +00:00
|
|
|
msg_printf(wup->project, MSG_ERROR,
|
|
|
|
"Failed to open core-to-app prefs file %s",
|
|
|
|
init_data_path
|
|
|
|
);
|
2002-07-15 23:21:20 +00:00
|
|
|
return ERR_FOPEN;
|
2002-06-10 22:59:15 +00:00
|
|
|
}
|
2003-05-07 23:42:17 +00:00
|
|
|
|
2003-05-09 20:33:57 +00:00
|
|
|
// make a unique key for core/app shared memory segment
|
|
|
|
//
|
2003-05-07 23:42:17 +00:00
|
|
|
#ifdef _WIN32
|
2004-06-29 05:10:15 +00:00
|
|
|
int i = 0;
|
|
|
|
char szSharedMemoryName[256];
|
|
|
|
HANDLE hSharedMemoryHandle;
|
|
|
|
|
|
|
|
do {
|
|
|
|
memset(szSharedMemoryName, '\0', sizeof(szSharedMemoryName));
|
|
|
|
sprintf(szSharedMemoryName, "boinc_%d", slot);
|
|
|
|
i++;
|
|
|
|
} while((!(hSharedMemoryHandle = create_shmem(szSharedMemoryName, 1024, NULL))) || (1024 < i));
|
|
|
|
|
|
|
|
if (hSharedMemoryHandle)
|
|
|
|
CloseHandle(hSharedMemoryHandle);
|
|
|
|
|
|
|
|
if (1024 < i)
|
|
|
|
return ERR_SEMOP;
|
|
|
|
|
|
|
|
strcpy(aid.comm_obj_name, szSharedMemoryName);
|
2003-06-06 17:43:45 +00:00
|
|
|
#elif HAVE_SYS_IPC_H
|
2003-04-01 03:18:12 +00:00
|
|
|
aid.shm_key = ftok(init_data_path, slot);
|
|
|
|
#else
|
2003-06-06 17:43:45 +00:00
|
|
|
#error shared memory key generation unimplemented
|
2003-03-17 19:24:38 +00:00
|
|
|
#endif
|
2003-05-07 23:42:17 +00:00
|
|
|
|
2004-06-16 19:21:11 +00:00
|
|
|
aid.host_info = gstate.host_info;
|
2003-03-08 23:48:05 +00:00
|
|
|
retval = write_init_data_file(f, aid);
|
2002-08-24 00:41:25 +00:00
|
|
|
fclose(f);
|
2003-10-31 22:37:46 +00:00
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Start a task in a slot directory.
|
|
|
|
// This includes setting up soft links,
|
|
|
|
// passing preferences, and starting the process
|
|
|
|
//
|
|
|
|
// Current dir is top-level BOINC dir
|
|
|
|
//
|
|
|
|
int ACTIVE_TASK::start(bool first_time) {
|
|
|
|
char exec_name[256], file_path[256], link_path[256], buf[256], exec_path[256];
|
|
|
|
unsigned int i;
|
|
|
|
FILE_REF file_ref;
|
|
|
|
FILE_INFO* fip;
|
|
|
|
int retval;
|
|
|
|
char graphics_data_path[256], fd_init_path[256];
|
|
|
|
FILE *f;
|
|
|
|
GRAPHICS_INFO gi;
|
|
|
|
APP_INIT_DATA aid;
|
|
|
|
|
2004-04-08 08:15:23 +00:00
|
|
|
SCOPE_MSG_LOG scope_messages(log_messages, CLIENT_MSG_LOG::DEBUG_TASK);
|
2003-10-31 22:37:46 +00:00
|
|
|
scope_messages.printf("ACTIVE_TASK::start(first_time=%d)\n", first_time);
|
|
|
|
|
|
|
|
if (first_time) {
|
|
|
|
checkpoint_cpu_time = 0;
|
|
|
|
}
|
|
|
|
current_cpu_time = checkpoint_cpu_time;
|
2004-05-21 20:06:34 +00:00
|
|
|
episode_start_cpu_time = checkpoint_cpu_time;
|
2004-06-30 01:10:22 +00:00
|
|
|
cpu_time_at_last_sched = checkpoint_cpu_time;
|
2003-10-31 22:37:46 +00:00
|
|
|
fraction_done = 0;
|
|
|
|
|
|
|
|
gi.xsize = 800;
|
|
|
|
gi.ysize = 600;
|
|
|
|
gi.refresh_period = 0.1;
|
|
|
|
|
|
|
|
retval = write_app_init_file(aid);
|
|
|
|
if (retval) return retval;
|
2002-06-08 00:55:25 +00:00
|
|
|
|
2002-09-11 21:41:42 +00:00
|
|
|
sprintf(graphics_data_path, "%s%s%s", slot_dir, PATH_SEPARATOR, GRAPHICS_DATA_FILE);
|
2003-12-24 00:50:51 +00:00
|
|
|
f = boinc_fopen(graphics_data_path, "w");
|
2002-09-11 21:41:42 +00:00
|
|
|
if (!f) {
|
2003-10-02 18:51:38 +00:00
|
|
|
msg_printf(wup->project, MSG_ERROR,
|
|
|
|
"Failed to open core-to-app graphics prefs file %s",
|
|
|
|
graphics_data_path
|
|
|
|
);
|
2002-09-11 21:41:42 +00:00
|
|
|
return ERR_FOPEN;
|
|
|
|
}
|
2002-09-17 21:54:59 +00:00
|
|
|
retval = write_graphics_file(f, &gi);
|
2002-09-11 21:41:42 +00:00
|
|
|
fclose(f);
|
|
|
|
|
2002-08-24 00:41:25 +00:00
|
|
|
sprintf(fd_init_path, "%s%s%s", slot_dir, PATH_SEPARATOR, FD_INIT_FILE);
|
2003-12-24 00:50:51 +00:00
|
|
|
f = boinc_fopen(fd_init_path, "w");
|
2002-08-24 00:41:25 +00:00
|
|
|
if (!f) {
|
2003-06-03 22:47:15 +00:00
|
|
|
msg_printf(wup->project, MSG_ERROR, "Failed to open init file %s", fd_init_path);
|
2002-07-15 23:21:20 +00:00
|
|
|
return ERR_FOPEN;
|
2002-06-20 23:46:51 +00:00
|
|
|
}
|
2002-04-30 22:22:54 +00:00
|
|
|
|
2002-08-05 00:29:34 +00:00
|
|
|
// make soft links to the executable(s)
|
2002-06-20 23:46:51 +00:00
|
|
|
//
|
|
|
|
for (i=0; i<app_version->app_files.size(); i++) {
|
2003-05-20 00:03:39 +00:00
|
|
|
FILE_REF fref = app_version->app_files[i];
|
|
|
|
fip = fref.file_info;
|
2002-06-20 23:46:51 +00:00
|
|
|
get_pathname(fip, file_path);
|
2003-05-20 00:03:39 +00:00
|
|
|
if (fref.main_program) {
|
2003-04-03 18:35:40 +00:00
|
|
|
safe_strcpy(exec_name, fip->name);
|
|
|
|
safe_strcpy(exec_path, file_path);
|
2002-06-20 23:46:51 +00:00
|
|
|
}
|
|
|
|
if (first_time) {
|
2003-06-16 23:40:20 +00:00
|
|
|
sprintf(link_path, "%s%s%s", slot_dir, PATH_SEPARATOR, strlen(fref.open_name)?fref.open_name:fip->name);
|
|
|
|
sprintf(buf, "..%s..%s%s", PATH_SEPARATOR, PATH_SEPARATOR, file_path);
|
|
|
|
retval = boinc_link(buf, link_path);
|
2003-07-02 02:02:18 +00:00
|
|
|
scope_messages.printf("ACTIVE_TASK::start(): Linking %s to %s\n", file_path, link_path);
|
2002-06-20 23:46:51 +00:00
|
|
|
if (retval) {
|
2003-06-03 22:47:15 +00:00
|
|
|
msg_printf(wup->project, MSG_ERROR, "Can't link %s to %s", file_path, link_path);
|
2002-08-24 00:41:25 +00:00
|
|
|
fclose(f);
|
2002-06-20 23:46:51 +00:00
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// create symbolic links, and hook up descriptors, for input files
|
|
|
|
//
|
|
|
|
for (i=0; i<wup->input_files.size(); i++) {
|
|
|
|
file_ref = wup->input_files[i];
|
|
|
|
get_pathname(file_ref.file_info, file_path);
|
|
|
|
if (strlen(file_ref.open_name)) {
|
2002-05-17 22:33:57 +00:00
|
|
|
if (first_time) {
|
2002-09-25 18:33:26 +00:00
|
|
|
sprintf(link_path, "%s%s%s", slot_dir, PATH_SEPARATOR, file_ref.open_name);
|
2003-03-13 21:49:52 +00:00
|
|
|
sprintf(buf, "..%s..%s%s", PATH_SEPARATOR, PATH_SEPARATOR, file_path );
|
2003-07-02 02:02:18 +00:00
|
|
|
scope_messages.printf("ACTIVE_TASK::start(): link %s to %s\n", file_path, link_path);
|
2003-07-01 18:27:08 +00:00
|
|
|
if (file_ref.copy_file) {
|
2003-07-01 21:05:37 +00:00
|
|
|
retval = boinc_copy(file_path, link_path);
|
2003-07-01 18:27:08 +00:00
|
|
|
if (retval) {
|
|
|
|
msg_printf(wup->project, MSG_ERROR, "Can't copy %s to %s", file_path, link_path);
|
|
|
|
fclose(f);
|
|
|
|
return retval;
|
|
|
|
}
|
2004-04-03 01:26:40 +00:00
|
|
|
} else {
|
2003-07-01 18:27:08 +00:00
|
|
|
retval = boinc_link(buf, link_path);
|
|
|
|
if (retval) {
|
|
|
|
msg_printf(wup->project, MSG_ERROR, "Can't link %s to %s", file_path, link_path);
|
|
|
|
fclose(f);
|
|
|
|
return retval;
|
|
|
|
}
|
2002-04-30 22:22:54 +00:00
|
|
|
}
|
|
|
|
}
|
2002-06-20 23:46:51 +00:00
|
|
|
} else {
|
2003-03-13 21:49:52 +00:00
|
|
|
sprintf(buf, "..%s..%s%s", PATH_SEPARATOR, PATH_SEPARATOR, file_path);
|
2003-09-27 17:53:43 +00:00
|
|
|
retval = write_fd_init_file(f, buf, file_ref.fd, true);
|
2003-03-08 23:48:05 +00:00
|
|
|
if (retval) return retval;
|
2002-04-30 22:22:54 +00:00
|
|
|
}
|
2002-06-20 23:46:51 +00:00
|
|
|
}
|
2002-04-30 22:22:54 +00:00
|
|
|
|
2002-07-15 23:21:20 +00:00
|
|
|
// hook up the output files using BOINC soft links
|
2002-06-20 23:46:51 +00:00
|
|
|
//
|
|
|
|
for (i=0; i<result->output_files.size(); i++) {
|
|
|
|
file_ref = result->output_files[i];
|
|
|
|
get_pathname(file_ref.file_info, file_path);
|
|
|
|
if (strlen(file_ref.open_name)) {
|
|
|
|
if (first_time) {
|
2002-09-25 18:33:26 +00:00
|
|
|
sprintf(link_path, "%s%s%s", slot_dir, PATH_SEPARATOR, file_ref.open_name);
|
2003-03-13 21:49:52 +00:00
|
|
|
sprintf(buf, "..%s..%s%s", PATH_SEPARATOR, PATH_SEPARATOR, file_path );
|
2003-07-02 02:02:18 +00:00
|
|
|
scope_messages.printf("ACTIVE_TASK::start(): link %s to %s\n", file_path, link_path);
|
2003-03-13 21:49:52 +00:00
|
|
|
retval = boinc_link(buf, link_path);
|
2002-06-20 23:46:51 +00:00
|
|
|
if (retval) {
|
2003-06-03 22:47:15 +00:00
|
|
|
msg_printf(wup->project, MSG_ERROR, "Can't link %s to %s", file_path, link_path);
|
2002-08-24 00:41:25 +00:00
|
|
|
fclose(f);
|
2002-06-20 23:46:51 +00:00
|
|
|
return retval;
|
2002-04-30 22:22:54 +00:00
|
|
|
}
|
|
|
|
}
|
2002-06-20 23:46:51 +00:00
|
|
|
} else {
|
2003-03-13 21:49:52 +00:00
|
|
|
sprintf(buf, "..%s..%s%s", PATH_SEPARATOR, PATH_SEPARATOR, file_path);
|
2003-09-27 17:53:43 +00:00
|
|
|
retval = write_fd_init_file(f, buf, file_ref.fd, false);
|
2003-03-08 23:48:05 +00:00
|
|
|
if (retval) return retval;
|
2002-04-30 22:22:54 +00:00
|
|
|
}
|
2002-06-20 23:46:51 +00:00
|
|
|
}
|
|
|
|
|
2002-08-24 00:41:25 +00:00
|
|
|
fclose(f);
|
2002-06-20 23:46:51 +00:00
|
|
|
|
2003-11-02 22:51:49 +00:00
|
|
|
link_user_files();
|
|
|
|
|
2002-04-30 22:22:54 +00:00
|
|
|
#ifdef _WIN32
|
2002-07-05 05:43:57 +00:00
|
|
|
PROCESS_INFORMATION process_info;
|
|
|
|
STARTUPINFO startup_info;
|
2002-08-24 00:41:25 +00:00
|
|
|
char slotdirpath[256];
|
2002-11-19 00:28:33 +00:00
|
|
|
char cmd_line[512];
|
2002-06-20 23:46:51 +00:00
|
|
|
|
2004-05-21 20:06:34 +00:00
|
|
|
memset(&process_info, 0, sizeof(process_info));
|
|
|
|
memset(&startup_info, 0, sizeof(startup_info));
|
2002-07-05 05:43:57 +00:00
|
|
|
startup_info.cb = sizeof(startup_info);
|
|
|
|
startup_info.lpReserved = NULL;
|
|
|
|
startup_info.lpDesktop = "";
|
2002-06-20 23:46:51 +00:00
|
|
|
|
2003-03-18 19:37:09 +00:00
|
|
|
sprintf(buf, "%s%s", QUIT_PREFIX, aid.comm_obj_name);
|
2003-10-30 19:45:56 +00:00
|
|
|
quitRequestEvent = CreateEvent(0, FALSE, FALSE, buf);
|
2003-03-18 19:37:09 +00:00
|
|
|
|
2003-05-09 20:33:57 +00:00
|
|
|
// create core/app share mem segment
|
|
|
|
//
|
2003-03-18 19:37:09 +00:00
|
|
|
sprintf(buf, "%s%s", SHM_PREFIX, aid.comm_obj_name);
|
2004-07-08 03:38:52 +00:00
|
|
|
shm_handle = create_shmem(buf, sizeof(SHARED_MEM),
|
2003-05-09 20:33:57 +00:00
|
|
|
(void **)&app_client_shm.shm
|
|
|
|
);
|
2004-07-08 03:38:52 +00:00
|
|
|
if (shm_handle == NULL) return ERR_SHMGET;
|
2003-05-09 20:33:57 +00:00
|
|
|
app_client_shm.reset_msgs();
|
2003-03-18 19:37:09 +00:00
|
|
|
|
2002-08-22 20:19:18 +00:00
|
|
|
// NOTE: in Windows, stderr is redirected within boinc_init();
|
2002-06-20 23:46:51 +00:00
|
|
|
|
2003-03-13 21:49:52 +00:00
|
|
|
sprintf(cmd_line, "%s %s", exec_path, wup->command_line);
|
2004-04-23 00:05:16 +00:00
|
|
|
relative_to_absolute(slot_dir, slotdirpath);
|
2002-08-22 20:19:18 +00:00
|
|
|
if (!CreateProcess(exec_path,
|
2002-10-24 17:06:42 +00:00
|
|
|
cmd_line,
|
2002-08-22 20:19:18 +00:00
|
|
|
NULL,
|
|
|
|
NULL,
|
2002-06-20 23:46:51 +00:00
|
|
|
FALSE,
|
2002-11-05 21:16:00 +00:00
|
|
|
CREATE_NEW_PROCESS_GROUP|CREATE_NO_WINDOW|IDLE_PRIORITY_CLASS,
|
2002-06-20 23:46:51 +00:00
|
|
|
NULL,
|
2002-08-24 00:41:25 +00:00
|
|
|
slotdirpath,
|
2002-06-20 23:46:51 +00:00
|
|
|
&startup_info,
|
2002-08-22 20:19:18 +00:00
|
|
|
&process_info
|
|
|
|
)) {
|
2004-04-03 01:26:40 +00:00
|
|
|
char szError[1024];
|
|
|
|
windows_error_string(szError, sizeof(szError));
|
2004-02-04 19:14:39 +00:00
|
|
|
|
2003-06-02 22:23:06 +00:00
|
|
|
state = PROCESS_COULDNT_START;
|
|
|
|
result->active_task_state = PROCESS_COULDNT_START;
|
2004-02-04 19:14:39 +00:00
|
|
|
gstate.report_result_error(*result, ERR_EXEC, "CreateProcess() failed - %s", szError);
|
|
|
|
msg_printf(wup->project, MSG_ERROR, "CreateProcess() failed - %s", szError);
|
2004-01-19 19:14:59 +00:00
|
|
|
return ERR_EXEC;
|
2002-07-05 05:43:57 +00:00
|
|
|
}
|
2003-02-20 00:06:07 +00:00
|
|
|
pid = process_info.dwProcessId;
|
2002-07-05 05:43:57 +00:00
|
|
|
pid_handle = process_info.hProcess;
|
2002-11-19 00:28:33 +00:00
|
|
|
thread_handle = process_info.hThread;
|
2002-12-06 07:33:45 +00:00
|
|
|
#else
|
|
|
|
char* argv[100];
|
2003-07-02 02:02:18 +00:00
|
|
|
|
2003-05-07 23:42:17 +00:00
|
|
|
// Set up core/app shared memory seg
|
2003-03-17 19:24:38 +00:00
|
|
|
//
|
|
|
|
shm_key = aid.shm_key;
|
2004-07-08 17:59:46 +00:00
|
|
|
retval = create_shmem(
|
|
|
|
shm_key, sizeof(SHARED_MEM), (void**)&app_client_shm.shm
|
|
|
|
);
|
|
|
|
if (retval) {
|
|
|
|
msg_printf(
|
|
|
|
wup->project, MSG_ERROR, "Can't create shared mem: %d", retval
|
|
|
|
);
|
|
|
|
return retval;
|
2003-05-07 23:42:17 +00:00
|
|
|
}
|
2004-07-08 17:59:46 +00:00
|
|
|
app_client_shm.reset_msgs();
|
2003-07-02 02:02:18 +00:00
|
|
|
|
2002-12-06 07:33:45 +00:00
|
|
|
pid = fork();
|
2003-08-11 03:33:14 +00:00
|
|
|
if (pid == -1) {
|
|
|
|
state = PROCESS_COULDNT_START;
|
|
|
|
result->active_task_state = PROCESS_COULDNT_START;
|
2003-12-24 00:10:36 +00:00
|
|
|
gstate.report_result_error(*result, -1, "fork(): %s", strerror(errno));
|
2003-08-11 03:33:14 +00:00
|
|
|
msg_printf(wup->project, MSG_ERROR, "fork(): %s", strerror(errno));
|
2003-10-21 04:06:55 +00:00
|
|
|
return ERR_FORK;
|
2003-08-11 03:33:14 +00:00
|
|
|
}
|
2002-12-06 07:33:45 +00:00
|
|
|
if (pid == 0) {
|
|
|
|
// from here on we're running in a new process.
|
|
|
|
// If an error happens, exit nonzero so that the core client
|
|
|
|
// knows there was a problem.
|
2002-06-20 23:46:51 +00:00
|
|
|
|
2002-12-06 07:33:45 +00:00
|
|
|
// chdir() into the slot directory
|
|
|
|
//
|
|
|
|
retval = chdir(slot_dir);
|
|
|
|
if (retval) {
|
|
|
|
perror("chdir");
|
2003-08-01 22:58:40 +00:00
|
|
|
_exit(retval);
|
2002-12-06 07:33:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// hook up stderr to a specially-named file
|
|
|
|
//
|
|
|
|
freopen(STDERR_FILE, "a", stderr);
|
|
|
|
|
|
|
|
argv[0] = exec_name;
|
|
|
|
parse_command_line(wup->command_line, argv+1);
|
2003-07-02 02:02:18 +00:00
|
|
|
debug_print_argv(argv);
|
2003-06-03 23:27:34 +00:00
|
|
|
sprintf(buf, "..%s..%s%s", PATH_SEPARATOR, PATH_SEPARATOR, exec_path );
|
2003-03-13 21:49:52 +00:00
|
|
|
retval = execv(buf, argv);
|
2004-04-23 00:05:16 +00:00
|
|
|
msg_printf(wup->project, MSG_ERROR,
|
|
|
|
"execv(%s) failed: %d\n", buf, retval
|
|
|
|
);
|
2002-12-06 07:33:45 +00:00
|
|
|
perror("execv");
|
2003-12-12 20:53:03 +00:00
|
|
|
_exit(errno);
|
2002-12-06 07:33:45 +00:00
|
|
|
}
|
2003-07-02 02:02:18 +00:00
|
|
|
|
|
|
|
scope_messages.printf("ACTIVE_TASK::start(): forked process: pid %d\n", pid);
|
2003-08-11 03:33:14 +00:00
|
|
|
|
|
|
|
// set idle process priority
|
|
|
|
#ifdef HAVE_SETPRIORITY
|
|
|
|
if (setpriority(PRIO_PROCESS, pid, PROCESS_IDLE_PRIORITY)) {
|
|
|
|
perror("setpriority");
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2002-04-30 22:22:54 +00:00
|
|
|
#endif
|
|
|
|
state = PROCESS_RUNNING;
|
2002-12-07 00:56:51 +00:00
|
|
|
result->active_task_state = PROCESS_RUNNING;
|
2004-06-30 01:10:22 +00:00
|
|
|
scheduler_state = CPU_SCHED_RUNNING;
|
2002-04-30 22:22:54 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2003-05-22 20:47:56 +00:00
|
|
|
// Send a quit signal.
|
|
|
|
// Normally this is caught by the process, which can checkpoint
|
2002-07-15 23:21:20 +00:00
|
|
|
//
|
2002-12-06 07:33:45 +00:00
|
|
|
int ACTIVE_TASK::request_exit() {
|
2004-07-08 03:38:52 +00:00
|
|
|
app_client_shm.shm->process_control_request.send_msg("<quit/>");
|
|
|
|
return 0;
|
2002-12-06 07:33:45 +00:00
|
|
|
}
|
2002-11-19 00:28:33 +00:00
|
|
|
|
2003-05-22 20:47:56 +00:00
|
|
|
// send a kill signal.
|
|
|
|
// This is not caught by the process
|
|
|
|
//
|
2002-12-06 07:33:45 +00:00
|
|
|
int ACTIVE_TASK::kill_task() {
|
2002-07-05 19:20:00 +00:00
|
|
|
#ifdef _WIN32
|
2003-03-12 18:15:48 +00:00
|
|
|
return !TerminateProcess(pid_handle, -1);
|
2002-12-06 07:33:45 +00:00
|
|
|
#else
|
|
|
|
return kill(pid, SIGKILL);
|
2002-07-05 19:20:00 +00:00
|
|
|
#endif
|
2002-07-01 18:16:31 +00:00
|
|
|
}
|
|
|
|
|
2003-09-06 03:34:03 +00:00
|
|
|
#if !defined(HAVE_WAIT4) && defined(HAVE_WAIT3)
|
|
|
|
#include <map>
|
|
|
|
struct proc_info_t {
|
|
|
|
int status;
|
|
|
|
rusage r;
|
|
|
|
proc_info_t() {};
|
|
|
|
proc_info_t(int s, const rusage &ru);
|
|
|
|
};
|
|
|
|
|
|
|
|
proc_info_t::proc_info_t(int s, const rusage &ru) : status(s), r(ru) {}
|
|
|
|
|
|
|
|
pid_t wait4(pid_t pid, int *statusp, int options, struct rusage *rusagep) {
|
|
|
|
static std::map<pid_t,proc_info_t> proc_info;
|
|
|
|
pid_t tmp_pid=0;
|
|
|
|
|
|
|
|
if (!pid) {
|
|
|
|
return wait3(statusp,options,rusagep);
|
|
|
|
} else {
|
|
|
|
if (proc_info.find(pid) == proc_info.end()) {
|
|
|
|
do {
|
|
|
|
tmp_pid=wait3(statusp,options,rusagep);
|
|
|
|
if ((tmp_pid>0) && (tmp_pid != pid)) {
|
2004-04-03 01:26:40 +00:00
|
|
|
proc_info[tmp_pid]=proc_info_t(*statusp,*rusagep);
|
|
|
|
if (!(options && WNOHANG)) {
|
|
|
|
tmp_pid=0;
|
|
|
|
}
|
2003-09-06 03:34:03 +00:00
|
|
|
} else {
|
2004-04-03 01:26:40 +00:00
|
|
|
return pid;
|
2003-09-06 03:34:03 +00:00
|
|
|
}
|
|
|
|
} while (!tmp_pid);
|
|
|
|
} else {
|
|
|
|
*statusp=proc_info[pid].status;
|
|
|
|
*rusagep=proc_info[pid].r;
|
|
|
|
proc_info.erase(pid);
|
|
|
|
return pid;
|
|
|
|
}
|
2003-09-08 06:01:41 +00:00
|
|
|
}
|
2003-09-06 03:34:03 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2004-04-03 01:26:40 +00:00
|
|
|
// We have sent a quit signal to the process; see if it's exited.
|
|
|
|
// This is called when the core client exits,
|
|
|
|
// or when a project is detached or reset
|
|
|
|
//
|
2003-03-11 22:18:01 +00:00
|
|
|
bool ACTIVE_TASK::task_exited() {
|
2004-03-30 23:05:34 +00:00
|
|
|
bool exited = false;
|
|
|
|
if (state != PROCESS_RUNNING) return true;
|
2003-03-11 22:18:01 +00:00
|
|
|
#ifdef _WIN32
|
|
|
|
unsigned long exit_code;
|
|
|
|
if (GetExitCodeProcess(pid_handle, &exit_code)) {
|
|
|
|
if (exit_code != STILL_ACTIVE) {
|
2004-03-30 23:05:34 +00:00
|
|
|
exited = true;
|
2003-03-11 22:18:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
int my_pid, stat;
|
2003-06-02 23:27:44 +00:00
|
|
|
struct rusage rs;
|
2003-03-11 22:18:01 +00:00
|
|
|
|
2003-06-02 23:27:44 +00:00
|
|
|
my_pid = wait4(pid, &stat, WNOHANG, &rs);
|
2003-03-11 22:18:01 +00:00
|
|
|
if (my_pid == pid) {
|
2004-03-30 23:05:34 +00:00
|
|
|
exited = true;
|
2003-03-11 22:18:01 +00:00
|
|
|
}
|
|
|
|
#endif
|
2004-03-30 23:05:34 +00:00
|
|
|
if (exited) {
|
|
|
|
state = PROCESS_EXITED;
|
|
|
|
}
|
|
|
|
return exited;
|
2003-03-11 22:18:01 +00:00
|
|
|
}
|
|
|
|
|
2004-06-30 01:10:22 +00:00
|
|
|
// preempts a task
|
2002-07-15 23:21:20 +00:00
|
|
|
//
|
2004-08-06 23:17:59 +00:00
|
|
|
int ACTIVE_TASK::preempt(bool quit_task) {
|
|
|
|
int retval;
|
2004-07-26 22:23:16 +00:00
|
|
|
|
2004-08-06 23:17:59 +00:00
|
|
|
if (quit_task) {
|
|
|
|
retval = request_exit();
|
|
|
|
pending_suspend_via_quit = true;
|
|
|
|
} else {
|
|
|
|
retval = suspend();
|
|
|
|
}
|
2002-08-05 00:29:34 +00:00
|
|
|
|
2004-05-24 19:00:26 +00:00
|
|
|
if (retval) {
|
2004-06-30 01:10:22 +00:00
|
|
|
msg_printf(
|
|
|
|
wup->project,
|
|
|
|
MSG_ERROR,
|
2004-08-06 23:17:59 +00:00
|
|
|
"ACTIVE_TASK::preempt(): could not %s active_task",
|
|
|
|
(quit_task ? "quit" : "suspend")
|
2004-05-24 19:00:26 +00:00
|
|
|
);
|
|
|
|
return retval;
|
|
|
|
}
|
2004-06-30 01:10:22 +00:00
|
|
|
scheduler_state = CPU_SCHED_PREEMPTED;
|
|
|
|
|
|
|
|
msg_printf(result->project, MSG_INFO,
|
2004-08-06 23:17:59 +00:00
|
|
|
"Preempting computation for result %s (%s)",
|
|
|
|
result->name,
|
|
|
|
(quit_task ? "quit" : "suspend")
|
2004-06-30 01:10:22 +00:00
|
|
|
);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Resume the task if it was previously running
|
|
|
|
// Otherwise, start it
|
|
|
|
//
|
|
|
|
int ACTIVE_TASK::resume_or_start() {
|
2004-07-29 17:18:36 +00:00
|
|
|
static const char process_start_types[3][15] = {
|
|
|
|
"Resuming",
|
|
|
|
"Restarting",
|
|
|
|
"Starting"
|
|
|
|
};
|
2004-06-30 01:10:22 +00:00
|
|
|
int retval;
|
2004-07-29 17:18:36 +00:00
|
|
|
int task_start_type;
|
2004-06-30 01:10:22 +00:00
|
|
|
|
2004-08-07 00:53:20 +00:00
|
|
|
if (pending_suspend_via_quit || state == PROCESS_UNINITIALIZED) {
|
|
|
|
if (pending_suspend_via_quit) {
|
|
|
|
// still have to destroy shm
|
|
|
|
//
|
|
|
|
#ifdef _WIN32
|
|
|
|
if (app_client_shm.shm) {
|
|
|
|
detach_shmem(shm_handle, app_client_shm.shm);
|
|
|
|
app_client_shm.shm = NULL;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
if (app_client_shm.shm) {
|
|
|
|
detach_shmem(app_client_shm.shm);
|
|
|
|
app_client_shm.shm = NULL;
|
|
|
|
}
|
|
|
|
destroy_shmem(shm_key);
|
|
|
|
#endif
|
|
|
|
pending_suspend_via_quit = false;
|
|
|
|
}
|
2004-06-30 01:10:22 +00:00
|
|
|
if (scheduler_state == CPU_SCHED_UNINITIALIZED) {
|
|
|
|
if (!boinc_file_exists(slot_dir)) {
|
|
|
|
make_slot_dir(slot);
|
|
|
|
}
|
|
|
|
retval = clean_out_dir(slot_dir);
|
|
|
|
retval = start(true);
|
2004-08-06 23:17:59 +00:00
|
|
|
task_start_type = TASK_START;
|
2004-06-30 01:10:22 +00:00
|
|
|
} else {
|
|
|
|
retval = start(false);
|
2004-08-06 23:17:59 +00:00
|
|
|
task_start_type = TASK_RESTART;
|
2004-06-30 01:10:22 +00:00
|
|
|
}
|
|
|
|
if (retval) return retval;
|
|
|
|
} else {
|
|
|
|
retval = unsuspend();
|
|
|
|
if (retval) {
|
|
|
|
msg_printf(
|
|
|
|
wup->project,
|
|
|
|
MSG_ERROR,
|
|
|
|
"ACTIVE_TASK::resume_preempted(): could not unsuspend active_task"
|
|
|
|
);
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
scheduler_state = CPU_SCHED_RUNNING;
|
2004-08-06 23:17:59 +00:00
|
|
|
task_start_type = TASK_RESUME;
|
2004-06-30 01:10:22 +00:00
|
|
|
}
|
2004-07-29 17:18:36 +00:00
|
|
|
msg_printf(result->project, MSG_INFO,
|
|
|
|
"%s computation for result %s using %s version %.2f",
|
|
|
|
process_start_types[task_start_type],
|
|
|
|
result->name,
|
|
|
|
app_version->app->name,
|
|
|
|
app_version->version_num/100.
|
|
|
|
);
|
2002-04-30 22:22:54 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2003-05-08 18:16:58 +00:00
|
|
|
#if 0
|
2003-04-01 07:36:19 +00:00
|
|
|
// Deallocate memory to prevent unneeded reporting of memory leaks
|
|
|
|
//
|
2003-03-19 18:46:58 +00:00
|
|
|
void ACTIVE_TASK_SET::free_mem() {
|
|
|
|
vector<ACTIVE_TASK*>::iterator at_iter;
|
2003-03-20 20:00:57 +00:00
|
|
|
ACTIVE_TASK *at;
|
2003-03-19 18:46:58 +00:00
|
|
|
|
|
|
|
at_iter = active_tasks.begin();
|
|
|
|
while (at_iter != active_tasks.end()) {
|
2003-03-20 20:00:57 +00:00
|
|
|
at = active_tasks[0];
|
2003-03-19 18:46:58 +00:00
|
|
|
at_iter = active_tasks.erase(at_iter);
|
2003-03-20 20:00:57 +00:00
|
|
|
delete at;
|
2003-03-19 18:46:58 +00:00
|
|
|
}
|
|
|
|
}
|
2003-05-08 18:16:58 +00:00
|
|
|
#endif
|
2003-03-19 18:46:58 +00:00
|
|
|
|
2003-05-22 20:47:56 +00:00
|
|
|
// Do period checks on running apps:
|
|
|
|
// - get latest CPU time and % done info
|
|
|
|
// - check if any has exited, and clean up
|
2003-11-25 17:17:21 +00:00
|
|
|
// - see if any has exceeded its CPU or disk space limits, and abort it
|
2002-04-30 22:22:54 +00:00
|
|
|
//
|
|
|
|
bool ACTIVE_TASK_SET::poll() {
|
2003-05-22 20:47:56 +00:00
|
|
|
bool action;
|
|
|
|
|
|
|
|
action = check_app_exited();
|
2004-07-08 03:38:52 +00:00
|
|
|
send_heartbeats();
|
|
|
|
send_trickle_downs();
|
2004-07-18 04:41:27 +00:00
|
|
|
graphics_poll();
|
2004-02-10 07:11:18 +00:00
|
|
|
action |= check_rsc_limits_exceeded();
|
2004-08-03 09:50:24 +00:00
|
|
|
if (get_msgs()) {
|
2004-04-03 01:26:40 +00:00
|
|
|
action = true;
|
2003-11-25 17:17:21 +00:00
|
|
|
}
|
2004-04-03 01:26:40 +00:00
|
|
|
if (action) {
|
2004-02-10 07:11:18 +00:00
|
|
|
gstate.set_client_state_dirty("ACTIVE_TASK_SET::poll");
|
2004-04-03 01:26:40 +00:00
|
|
|
}
|
2004-02-10 07:11:18 +00:00
|
|
|
return action;
|
2003-05-22 20:47:56 +00:00
|
|
|
}
|
2002-04-30 22:22:54 +00:00
|
|
|
|
2004-04-04 01:59:47 +00:00
|
|
|
bool ACTIVE_TASK::finish_file_present() {
|
|
|
|
char path[256];
|
|
|
|
sprintf(path, "%s%s%s", slot_dir, PATH_SEPARATOR, BOINC_FINISH_CALLED_FILE);
|
|
|
|
return boinc_file_exists(path);
|
|
|
|
}
|
|
|
|
|
2004-07-08 03:38:52 +00:00
|
|
|
void ACTIVE_TASK_SET::send_trickle_downs() {
|
2004-06-29 01:15:51 +00:00
|
|
|
unsigned int i;
|
|
|
|
ACTIVE_TASK* atp;
|
2004-07-02 04:49:17 +00:00
|
|
|
bool sent;
|
2004-06-29 01:15:51 +00:00
|
|
|
for (i=0; i<active_tasks.size(); i++) {
|
|
|
|
atp = active_tasks[i];
|
2004-07-09 18:24:08 +00:00
|
|
|
if (atp->state == PROCESS_IN_LIMBO
|
|
|
|
|| atp->state == PROCESS_UNINITIALIZED
|
|
|
|
) {
|
|
|
|
continue;
|
|
|
|
}
|
2004-07-02 04:49:17 +00:00
|
|
|
if (atp->have_trickle_down) {
|
2004-07-08 03:38:52 +00:00
|
|
|
sent = atp->app_client_shm.shm->trickle_down.send_msg("<have_trickle_down/>\n");
|
|
|
|
if (sent) atp->have_trickle_down = false;
|
2004-07-02 04:49:17 +00:00
|
|
|
}
|
2004-07-08 03:38:52 +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-07-09 18:11:15 +00:00
|
|
|
if (atp->state == PROCESS_IN_LIMBO
|
|
|
|
|| atp->state == PROCESS_UNINITIALIZED
|
|
|
|
) {
|
2004-07-08 03:38:52 +00:00
|
|
|
continue;
|
|
|
|
}
|
2004-07-18 04:41:27 +00:00
|
|
|
bool foo = atp->app_client_shm.shm->heartbeat.send_msg("<heartbeat/>\n");
|
|
|
|
//msg_printf(atp->wup->project, MSG_INFO, "send heartbeat: %d", foo );
|
2004-06-29 01:15:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-05-22 20:47:56 +00:00
|
|
|
bool ACTIVE_TASK_SET::check_app_exited() {
|
|
|
|
ACTIVE_TASK* atp;
|
2003-07-02 02:02:18 +00:00
|
|
|
|
2004-04-08 08:15:23 +00:00
|
|
|
SCOPE_MSG_LOG scope_messages(log_messages, CLIENT_MSG_LOG::DEBUG_TASK);
|
2003-07-02 02:02:18 +00:00
|
|
|
|
2002-06-06 18:42:01 +00:00
|
|
|
#ifdef _WIN32
|
2002-07-05 05:43:57 +00:00
|
|
|
unsigned long exit_code;
|
2002-08-22 22:28:51 +00:00
|
|
|
bool found = false;
|
2004-04-03 01:26:40 +00:00
|
|
|
unsigned int i;
|
2002-06-06 18:42:01 +00:00
|
|
|
|
2004-01-10 06:40:46 +00:00
|
|
|
for (i=0; i<active_tasks.size(); i++) {
|
2002-06-06 18:42:01 +00:00
|
|
|
atp = active_tasks[i];
|
2004-06-30 01:10:22 +00:00
|
|
|
if (atp->scheduler_state != CPU_SCHED_RUNNING) continue;
|
2004-08-06 23:17:59 +00:00
|
|
|
if (atp->state == PROCESS_IN_LIMBO ||
|
2004-08-06 23:32:14 +00:00
|
|
|
atp->state == PROCESS_UNINITIALIZED
|
2004-08-06 23:17:59 +00:00
|
|
|
) continue;
|
2002-08-05 00:29:34 +00:00
|
|
|
if (GetExitCodeProcess(atp->pid_handle, &exit_code)) {
|
|
|
|
if (exit_code != STILL_ACTIVE) {
|
2004-05-18 22:47:08 +00:00
|
|
|
scope_messages.printf("ACTIVE_TASK_SET::check_app_exited(): Process exited with code %d\n", exit_code);
|
2004-08-03 09:50:24 +00:00
|
|
|
atp->get_msg();
|
2003-12-13 01:40:28 +00:00
|
|
|
atp->result->final_cpu_time = atp->checkpoint_cpu_time;
|
2002-08-24 00:41:25 +00:00
|
|
|
found = true;
|
2002-12-06 07:33:45 +00:00
|
|
|
if (atp->state == PROCESS_ABORT_PENDING) {
|
|
|
|
atp->state = PROCESS_ABORTED;
|
2003-02-06 19:01:49 +00:00
|
|
|
atp->result->active_task_state = PROCESS_ABORTED;
|
2002-12-06 07:33:45 +00:00
|
|
|
} else {
|
|
|
|
atp->state = PROCESS_EXITED;
|
|
|
|
atp->exit_status = exit_code;
|
2004-04-04 01:59:47 +00:00
|
|
|
|
2003-02-06 19:01:49 +00:00
|
|
|
//if a nonzero error code, then report it
|
2004-04-04 01:59:47 +00:00
|
|
|
//
|
2003-02-20 00:06:07 +00:00
|
|
|
if (exit_code) {
|
2004-04-03 01:26:40 +00:00
|
|
|
char szError[1024];
|
2003-03-13 21:49:52 +00:00
|
|
|
gstate.report_result_error(
|
2003-02-20 00:06:07 +00:00
|
|
|
*(atp->result), 0,
|
2004-02-05 06:42:11 +00:00
|
|
|
"%s - exit code %d (0x%x)",
|
2004-02-07 06:21:22 +00:00
|
|
|
windows_format_error_string(exit_code, szError, sizeof(szError)),
|
2004-04-03 01:26:40 +00:00
|
|
|
exit_code, exit_code
|
2003-02-20 00:06:07 +00:00
|
|
|
);
|
2004-04-04 01:59:47 +00:00
|
|
|
} else {
|
2004-08-06 23:17:59 +00:00
|
|
|
if (atp->pending_suspend_via_quit) {
|
|
|
|
atp->pending_suspend_via_quit = false;
|
|
|
|
atp->state = PROCESS_UNINITIALIZED;
|
|
|
|
if (atp->app_client_shm.shm) {
|
2004-08-06 23:35:19 +00:00
|
|
|
detach_shmem(atp->shm_handle, atp->app_client_shm.shm);
|
2004-08-06 23:17:59 +00:00
|
|
|
atp->app_client_shm.shm = NULL;
|
|
|
|
}
|
|
|
|
} else if (!atp->finish_file_present()) {
|
2004-04-04 01:59:47 +00:00
|
|
|
atp->state = PROCESS_IN_LIMBO;
|
|
|
|
}
|
2004-08-06 23:17:59 +00:00
|
|
|
return true;
|
2003-02-06 19:01:49 +00:00
|
|
|
}
|
2004-04-04 01:59:47 +00:00
|
|
|
atp->result->exit_status = atp->exit_status;
|
|
|
|
atp->result->active_task_state = PROCESS_EXITED;
|
2002-12-06 07:33:45 +00:00
|
|
|
}
|
2002-11-22 00:13:47 +00:00
|
|
|
atp->read_stderr_file();
|
|
|
|
clean_out_dir(atp->slot_dir);
|
2003-05-22 20:47:56 +00:00
|
|
|
|
2002-07-05 05:43:57 +00:00
|
|
|
}
|
|
|
|
}
|
2002-06-06 18:42:01 +00:00
|
|
|
}
|
2002-12-06 07:33:45 +00:00
|
|
|
if (found) return true;
|
2002-12-05 19:13:06 +00:00
|
|
|
#else
|
2002-06-06 18:42:01 +00:00
|
|
|
int pid;
|
2002-08-09 23:16:37 +00:00
|
|
|
int stat;
|
2003-06-02 23:27:44 +00:00
|
|
|
struct rusage rs;
|
2002-06-06 18:42:01 +00:00
|
|
|
|
2003-06-02 23:27:44 +00:00
|
|
|
pid = wait4(0, &stat, WNOHANG, &rs);
|
2002-12-06 07:33:45 +00:00
|
|
|
if (pid > 0) {
|
2003-07-02 02:02:18 +00:00
|
|
|
scope_messages.printf("ACTIVE_TASK_SET::check_app_exited(): process %d is done\n", pid);
|
2002-12-06 07:33:45 +00:00
|
|
|
atp = lookup_pid(pid);
|
|
|
|
if (!atp) {
|
2003-07-03 05:01:29 +00:00
|
|
|
msg_printf(NULL, MSG_ERROR, "ACTIVE_TASK_SET::check_app_exited(): pid %d not found\n", pid);
|
2002-12-06 07:33:45 +00:00
|
|
|
return true;
|
|
|
|
}
|
2004-08-03 09:50:24 +00:00
|
|
|
atp->get_msg();
|
2003-12-05 20:49:52 +00:00
|
|
|
atp->result->final_cpu_time = atp->checkpoint_cpu_time;
|
2002-12-06 07:33:45 +00:00
|
|
|
if (atp->state == PROCESS_ABORT_PENDING) {
|
|
|
|
atp->state = PROCESS_ABORTED;
|
2003-03-17 19:24:38 +00:00
|
|
|
atp->result->active_task_state = PROCESS_ABORTED;
|
2002-12-06 07:33:45 +00:00
|
|
|
} else {
|
|
|
|
if (WIFEXITED(stat)) {
|
|
|
|
atp->state = PROCESS_EXITED;
|
|
|
|
atp->exit_status = WEXITSTATUS(stat);
|
2003-03-13 21:49:52 +00:00
|
|
|
|
2004-04-04 01:59:47 +00:00
|
|
|
// If exit_status is nonzero,
|
|
|
|
// then we don't need to upload the output files
|
2003-03-13 21:49:52 +00:00
|
|
|
//
|
2004-04-04 01:59:47 +00:00
|
|
|
if (atp->exit_status) {
|
2003-03-13 21:49:52 +00:00
|
|
|
gstate.report_result_error(
|
2003-02-20 00:06:07 +00:00
|
|
|
*(atp->result), 0,
|
2003-11-04 22:22:06 +00:00
|
|
|
"process exited with code %d (0x%x)",
|
|
|
|
atp->exit_status, atp->exit_status
|
2003-02-20 00:06:07 +00:00
|
|
|
);
|
2004-04-04 01:59:47 +00:00
|
|
|
} else {
|
2004-08-06 23:17:59 +00:00
|
|
|
if (atp->pending_suspend_via_quit) {
|
|
|
|
atp->pending_suspend_via_quit = false;
|
|
|
|
atp->state = PROCESS_UNINITIALIZED;
|
|
|
|
|
|
|
|
// destroy shm, since restarting app will re-create it
|
|
|
|
//
|
|
|
|
if (atp->app_client_shm.shm) {
|
|
|
|
detach_shmem(atp->app_client_shm.shm);
|
|
|
|
atp->app_client_shm.shm = NULL;
|
|
|
|
}
|
|
|
|
destroy_shmem(atp->shm_key);
|
|
|
|
} else if (!atp->finish_file_present()) {
|
2004-04-04 01:59:47 +00:00
|
|
|
// The process looks like it exited normally
|
|
|
|
// but there's no "finish file".
|
|
|
|
// Assume it was externally killed,
|
|
|
|
// and just leave it there
|
|
|
|
// (assume user is about to exit core client)
|
|
|
|
//
|
|
|
|
atp->state = PROCESS_IN_LIMBO;
|
|
|
|
}
|
2004-08-06 23:17:59 +00:00
|
|
|
return true;
|
2003-02-06 19:01:49 +00:00
|
|
|
}
|
2004-04-04 01:59:47 +00:00
|
|
|
atp->result->exit_status = atp->exit_status;
|
|
|
|
atp->result->active_task_state = PROCESS_EXITED;
|
|
|
|
scope_messages.printf(
|
|
|
|
"ACTIVE_TASK_SET::check_app_exited(): process exited: status %d\n",
|
|
|
|
atp->exit_status
|
|
|
|
);
|
2002-12-06 07:33:45 +00:00
|
|
|
} else if (WIFSIGNALED(stat)) {
|
2004-05-05 17:48:39 +00:00
|
|
|
int signal = WTERMSIG(stat);
|
|
|
|
|
|
|
|
// if the process was externally killed, allow it to restart.
|
|
|
|
//
|
2004-05-11 04:39:25 +00:00
|
|
|
switch(signal) {
|
|
|
|
case SIGHUP:
|
|
|
|
case SIGINT:
|
|
|
|
case SIGQUIT:
|
|
|
|
case SIGKILL:
|
|
|
|
case SIGTERM:
|
|
|
|
case SIGSTOP:
|
2004-05-05 17:48:39 +00:00
|
|
|
atp->state = PROCESS_IN_LIMBO;
|
|
|
|
return true;
|
|
|
|
}
|
2004-04-03 01:26:40 +00:00
|
|
|
atp->exit_status = stat;
|
|
|
|
atp->result->exit_status = atp->exit_status;
|
2002-12-06 07:33:45 +00:00
|
|
|
atp->state = PROCESS_WAS_SIGNALED;
|
2004-05-05 17:48:39 +00:00
|
|
|
atp->signal = signal;
|
2002-12-07 00:56:51 +00:00
|
|
|
atp->result->signal = atp->signal;
|
2003-02-06 19:01:49 +00:00
|
|
|
atp->result->active_task_state = PROCESS_WAS_SIGNALED;
|
2003-03-13 21:49:52 +00:00
|
|
|
gstate.report_result_error(
|
2003-10-30 20:00:30 +00:00
|
|
|
*(atp->result), 0, "process got signal %d", atp->signal
|
2003-02-20 00:06:07 +00:00
|
|
|
);
|
2003-10-30 20:00:30 +00:00
|
|
|
scope_messages.printf("ACTIVE_TASK_SET::check_app_exited(): process got signal %d\n", atp->signal);
|
2002-12-06 07:33:45 +00:00
|
|
|
} else {
|
2003-02-06 19:01:49 +00:00
|
|
|
atp->state = PROCESS_EXIT_UNKNOWN;
|
2003-02-20 00:06:07 +00:00
|
|
|
atp->result->state = PROCESS_EXIT_UNKNOWN;
|
2002-12-06 07:33:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
atp->read_stderr_file();
|
|
|
|
clean_out_dir(atp->slot_dir);
|
|
|
|
|
2002-04-30 22:22:54 +00:00
|
|
|
return true;
|
|
|
|
}
|
2002-06-06 18:42:01 +00:00
|
|
|
#endif
|
2003-05-22 20:47:56 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// if an app has exceeded its maximum CPU time, abort it
|
|
|
|
//
|
2003-05-28 19:56:53 +00:00
|
|
|
bool ACTIVE_TASK::check_max_cpu_exceeded() {
|
|
|
|
if (current_cpu_time > max_cpu_time) {
|
2003-06-03 22:47:15 +00:00
|
|
|
msg_printf(result->project, MSG_INFO,
|
2003-05-28 19:56:53 +00:00
|
|
|
"Aborting result %s: exceeded CPU time limit %f\n",
|
2004-02-10 07:11:18 +00:00
|
|
|
result->name, max_cpu_time
|
2004-04-03 01:26:40 +00:00
|
|
|
);
|
2004-03-31 23:39:12 +00:00
|
|
|
abort_task("Maximum CPU time exceeded");
|
2003-05-28 19:56:53 +00:00
|
|
|
return true;
|
2002-12-06 07:33:45 +00:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2002-11-22 00:13:47 +00:00
|
|
|
|
2003-05-22 20:47:56 +00:00
|
|
|
// if an app has exceeded its maximum disk usage, abort it
|
|
|
|
//
|
2003-05-28 19:56:53 +00:00
|
|
|
bool ACTIVE_TASK::check_max_disk_exceeded() {
|
2003-05-22 20:47:56 +00:00
|
|
|
double disk_usage;
|
|
|
|
int retval;
|
|
|
|
|
2003-05-28 19:56:53 +00:00
|
|
|
// don't do disk check too often
|
|
|
|
//
|
|
|
|
retval = current_disk_usage(disk_usage);
|
|
|
|
if (retval) {
|
2003-06-03 22:47:15 +00:00
|
|
|
msg_printf(0, MSG_ERROR, "Can't get application disk usage");
|
2003-05-28 19:56:53 +00:00
|
|
|
} else {
|
|
|
|
if (disk_usage > max_disk_usage) {
|
2003-07-03 05:01:29 +00:00
|
|
|
msg_printf(
|
|
|
|
result->project, MSG_INFO,
|
2004-04-03 01:26:40 +00:00
|
|
|
"Aborting result %s: exceeded disk limit: %f > %f\n",
|
2004-01-17 18:36:17 +00:00
|
|
|
result->name, disk_usage, max_disk_usage
|
2003-07-03 05:01:29 +00:00
|
|
|
);
|
2004-03-31 23:39:12 +00:00
|
|
|
abort_task("Maximum disk usage exceeded");
|
2003-05-28 19:56:53 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2003-06-17 18:59:36 +00:00
|
|
|
#if 0
|
2003-05-28 19:56:53 +00:00
|
|
|
// if an app has exceeded its maximum allowed memory, abort it
|
2003-05-22 20:47:56 +00:00
|
|
|
//
|
2003-05-28 19:56:53 +00:00
|
|
|
bool ACTIVE_TASK::check_max_mem_exceeded() {
|
2003-06-03 22:47:15 +00:00
|
|
|
// TODO: calculate working set size elsewhere
|
2003-06-16 23:40:20 +00:00
|
|
|
if (working_set_size > max_mem_usage || working_set_size/1048576 > gstate.global_prefs.max_memory_mbytes) {
|
2003-07-03 05:01:29 +00:00
|
|
|
msg_printf(
|
|
|
|
result->project, MSG_INFO,
|
|
|
|
"Aborting result %s: exceeded memory limit %f\n",
|
|
|
|
result->name,
|
|
|
|
min(max_mem_usage, gstate.global_prefs.max_memory_mbytes*1048576)
|
|
|
|
);
|
2004-03-31 23:39:12 +00:00
|
|
|
abort_task("Maximum memory usage exceeded");
|
2003-05-28 19:56:53 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2003-06-17 18:59:36 +00:00
|
|
|
#endif
|
2003-05-28 19:56:53 +00:00
|
|
|
|
2004-07-29 17:18:36 +00:00
|
|
|
bool ACTIVE_TASK::check_max_mem_exceeded() {
|
2004-08-06 23:17:59 +00:00
|
|
|
if (max_mem_usage != 0 && resident_set_size*1024 > max_mem_usage) {
|
2004-07-29 17:18:36 +00:00
|
|
|
msg_printf(
|
|
|
|
result->project, MSG_INFO,
|
|
|
|
"Aborting result %s: exceeded memory limit %f\n",
|
|
|
|
result->name,
|
|
|
|
max_mem_usage
|
|
|
|
);
|
|
|
|
abort_task("Maximum memory usage exceeded");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2004-08-06 23:17:59 +00:00
|
|
|
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];
|
|
|
|
if (atp->state != PROCESS_RUNNING) continue;
|
|
|
|
total_vm_usage += atp->vm_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (total_vm_usage > vm_limit);
|
|
|
|
}
|
|
|
|
|
2003-05-28 19:56:53 +00:00
|
|
|
// 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;
|
|
|
|
static time_t last_disk_check_time = 0;
|
|
|
|
|
|
|
|
for (j=0;j<active_tasks.size();j++) {
|
|
|
|
atp = active_tasks[j];
|
2004-06-30 01:10:22 +00:00
|
|
|
if (atp->scheduler_state != CPU_SCHED_RUNNING) continue;
|
2004-04-03 01:26:40 +00:00
|
|
|
if (atp->state != PROCESS_RUNNING) continue;
|
2003-05-28 19:56:53 +00:00
|
|
|
if (atp->check_max_cpu_exceeded()) return true;
|
2004-07-29 17:18:36 +00:00
|
|
|
else if (atp->check_max_mem_exceeded()) return true;
|
2003-05-28 19:56:53 +00:00
|
|
|
else if (time(0)>last_disk_check_time + gstate.global_prefs.disk_interval) {
|
|
|
|
last_disk_check_time = time(0);
|
|
|
|
if (atp->check_max_disk_exceeded()) return true;
|
2003-05-22 20:47:56 +00:00
|
|
|
}
|
|
|
|
}
|
2003-05-28 19:56:53 +00:00
|
|
|
|
2003-05-22 20:47:56 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2003-10-19 02:54:35 +00:00
|
|
|
// If process is running, send it a kill signal
|
2004-03-31 23:39:12 +00:00
|
|
|
// This is done when app has exceeded CPU, disk, or mem limits
|
2003-07-02 02:02:18 +00:00
|
|
|
//
|
2004-03-31 23:39:12 +00:00
|
|
|
int ACTIVE_TASK::abort_task(char* msg) {
|
2003-09-02 03:38:04 +00:00
|
|
|
if (state == PROCESS_RUNNING) {
|
|
|
|
state = PROCESS_ABORT_PENDING;
|
|
|
|
result->active_task_state = PROCESS_ABORT_PENDING;
|
|
|
|
kill_task();
|
|
|
|
} else {
|
|
|
|
state = PROCESS_ABORTED;
|
|
|
|
}
|
2004-03-31 23:39:12 +00:00
|
|
|
gstate.report_result_error(*result, ERR_RSC_LIMIT_EXCEEDED, msg);
|
2003-09-02 03:38:04 +00:00
|
|
|
return 0;
|
2002-11-22 00:13:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// check for the stderr file, copy to result record
|
|
|
|
//
|
|
|
|
bool ACTIVE_TASK::read_stderr_file() {
|
2003-06-27 23:13:15 +00:00
|
|
|
char stderr_file[MAX_BLOB_LEN];
|
2002-11-22 00:13:47 +00:00
|
|
|
char path[256];
|
|
|
|
int n;
|
|
|
|
|
|
|
|
sprintf(path, "%s%s%s", slot_dir, PATH_SEPARATOR, STDERR_FILE);
|
2004-03-01 19:11:12 +00:00
|
|
|
if (boinc_file_exists(path)) {
|
|
|
|
FILE* f = fopen(path, "r");
|
2003-07-21 12:42:41 +00:00
|
|
|
n = fread(stderr_file, 1, sizeof(stderr_file)-1, f);
|
2002-04-30 22:22:54 +00:00
|
|
|
fclose(f);
|
2003-07-21 12:42:41 +00:00
|
|
|
if (n < 0) return false;
|
|
|
|
stderr_file[n] = '\0';
|
2003-06-27 23:13:15 +00:00
|
|
|
result->stderr_out += "<stderr_txt>\n";
|
|
|
|
result->stderr_out += stderr_file;
|
2004-03-22 23:02:45 +00:00
|
|
|
const char* stderr_txt_close = "\n</stderr_txt>\n";
|
2004-03-23 01:44:13 +00:00
|
|
|
|
|
|
|
// truncate stderr output to 64KB;
|
|
|
|
// it's unlikely that more than that will be useful
|
|
|
|
//
|
|
|
|
result->stderr_out = result->stderr_out.substr(0, MAX_BLOB_LEN-1-strlen(stderr_txt_close));
|
2004-03-22 23:02:45 +00:00
|
|
|
result->stderr_out += stderr_txt_close;
|
2003-02-20 00:06:07 +00:00
|
|
|
return true;
|
2002-04-30 22:22:54 +00:00
|
|
|
}
|
2002-12-05 21:56:33 +00:00
|
|
|
return false;
|
2002-04-30 22:22:54 +00:00
|
|
|
}
|
|
|
|
|
2004-05-21 20:06:34 +00:00
|
|
|
// tell a running app to reread project preferences.
|
|
|
|
// This is called when project prefs change,
|
|
|
|
// or when a user file has finished downloading.
|
|
|
|
//
|
2003-10-31 22:37:46 +00:00
|
|
|
int ACTIVE_TASK::request_reread_prefs() {
|
|
|
|
int retval;
|
|
|
|
APP_INIT_DATA aid;
|
2004-07-13 13:54:09 +00:00
|
|
|
|
2003-11-02 22:51:49 +00:00
|
|
|
link_user_files();
|
|
|
|
|
2003-10-31 22:37:46 +00:00
|
|
|
retval = write_app_init_file(aid);
|
|
|
|
if (retval) return retval;
|
2004-07-08 03:38:52 +00:00
|
|
|
app_client_shm.shm->graphics_request.send_msg(
|
|
|
|
xml_graphics_modes[MODE_REREAD_PREFS]
|
2003-10-30 23:23:52 +00:00
|
|
|
);
|
2003-10-31 22:37:46 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-05-21 20:06:34 +00:00
|
|
|
// tell all running apps of a project to reread prefs
|
|
|
|
//
|
2003-10-31 22:37:46 +00:00
|
|
|
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-07-13 00:13:29 +00:00
|
|
|
if (atp->state == PROCESS_IN_LIMBO
|
|
|
|
|| atp->state == PROCESS_UNINITIALIZED
|
|
|
|
) {
|
|
|
|
continue;
|
|
|
|
}
|
2003-10-31 22:37:46 +00:00
|
|
|
atp->request_reread_prefs();
|
|
|
|
}
|
2003-10-30 23:23:52 +00:00
|
|
|
}
|
|
|
|
|
2003-05-07 23:42:17 +00:00
|
|
|
|
2003-10-19 02:54:35 +00:00
|
|
|
// send quit signal to all tasks in the project
|
2004-04-03 01:26:40 +00:00
|
|
|
// (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
|
2003-05-22 20:47:56 +00:00
|
|
|
//
|
2003-10-19 02:54:35 +00:00
|
|
|
int ACTIVE_TASK_SET::exit_tasks(PROJECT* proj) {
|
|
|
|
request_tasks_exit(proj);
|
2003-05-22 20:47:56 +00:00
|
|
|
|
2003-06-27 21:15:25 +00:00
|
|
|
// Wait 5 seconds for them to exit normally; if they don't then kill them
|
2003-05-22 20:47:56 +00:00
|
|
|
//
|
2003-10-19 02:54:35 +00:00
|
|
|
if (wait_for_exit(5, proj)) {
|
|
|
|
kill_tasks(proj);
|
2003-05-22 20:47:56 +00:00
|
|
|
}
|
2003-10-19 02:54:35 +00:00
|
|
|
wait_for_exit(5, proj);
|
2003-05-22 20:47:56 +00:00
|
|
|
|
2003-11-25 17:17:21 +00:00
|
|
|
// get final checkpoint_cpu_times
|
|
|
|
//
|
2004-08-03 09:50:24 +00:00
|
|
|
get_msgs();
|
2003-07-02 02:02:18 +00:00
|
|
|
|
2003-05-22 20:47:56 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2003-10-19 02:54:35 +00:00
|
|
|
// 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
|
2003-03-11 22:18:01 +00:00
|
|
|
//
|
2003-10-19 02:54:35 +00:00
|
|
|
int ACTIVE_TASK_SET::wait_for_exit(double wait_time, PROJECT* proj) {
|
2003-03-13 21:49:52 +00:00
|
|
|
bool all_exited;
|
2003-03-17 19:24:38 +00:00
|
|
|
unsigned int i,n;
|
|
|
|
ACTIVE_TASK *atp;
|
2003-03-11 22:18:01 +00:00
|
|
|
|
2003-03-13 21:49:52 +00:00
|
|
|
for (i=0; i<10; i++) {
|
2003-03-11 22:18:01 +00:00
|
|
|
all_exited = true;
|
|
|
|
|
2003-03-13 21:49:52 +00:00
|
|
|
for (n=0; n<active_tasks.size(); n++) {
|
2003-03-11 22:18:01 +00:00
|
|
|
atp = active_tasks[n];
|
2003-10-19 02:54:35 +00:00
|
|
|
if (proj && atp->wup->project != proj) continue;
|
2003-03-11 22:18:01 +00:00
|
|
|
if (!atp->task_exited()) {
|
|
|
|
all_exited = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-03-17 19:24:38 +00:00
|
|
|
if (all_exited) return 0;
|
2003-10-19 02:54:35 +00:00
|
|
|
boinc_sleep(wait_time/10.0);
|
2003-03-11 22:18:01 +00:00
|
|
|
}
|
|
|
|
|
2003-10-21 04:06:55 +00:00
|
|
|
return ERR_NOT_EXITED;
|
2003-03-11 22:18:01 +00:00
|
|
|
}
|
|
|
|
|
2003-10-19 02:54:35 +00:00
|
|
|
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);
|
2004-03-30 23:05:34 +00:00
|
|
|
delete atp;
|
2003-10-19 02:54:35 +00:00
|
|
|
} else {
|
|
|
|
task_iter++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2002-07-15 23:21:20 +00:00
|
|
|
// Find the ACTIVE_TASK in the current set with the matching PID
|
|
|
|
//
|
2002-04-30 22:22:54 +00:00
|
|
|
ACTIVE_TASK* ACTIVE_TASK_SET::lookup_pid(int pid) {
|
|
|
|
unsigned int i;
|
|
|
|
ACTIVE_TASK* atp;
|
2002-08-05 00:29:34 +00:00
|
|
|
|
2002-04-30 22:22:54 +00:00
|
|
|
for (i=0; i<active_tasks.size(); i++) {
|
|
|
|
atp = active_tasks[i];
|
|
|
|
if (atp->pid == pid) return atp;
|
|
|
|
}
|
2002-07-15 23:21:20 +00:00
|
|
|
return NULL;
|
2002-04-30 22:22:54 +00:00
|
|
|
}
|
|
|
|
|
2003-08-12 20:28:55 +00:00
|
|
|
// Find the ACTIVE_TASK in the current set with the matching result
|
|
|
|
//
|
|
|
|
ACTIVE_TASK* ACTIVE_TASK_SET::lookup_result(RESULT* result) {
|
|
|
|
for (active_tasks_v::iterator i = active_tasks.begin();
|
|
|
|
i != active_tasks.end(); ++i)
|
|
|
|
{
|
|
|
|
ACTIVE_TASK* atp = *i;
|
|
|
|
if (atp->result == result) {
|
|
|
|
return atp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2002-12-06 07:33:45 +00:00
|
|
|
// suspend all currently running tasks
|
2002-07-15 23:21:20 +00:00
|
|
|
//
|
2004-08-06 23:17:59 +00:00
|
|
|
void ACTIVE_TASK_SET::suspend_all(bool leave_apps_in_memory) {
|
2002-04-30 22:22:54 +00:00
|
|
|
unsigned int i;
|
|
|
|
ACTIVE_TASK* atp;
|
|
|
|
for (i=0; i<active_tasks.size(); i++) {
|
|
|
|
atp = active_tasks[i];
|
2004-06-30 01:10:22 +00:00
|
|
|
if (atp->scheduler_state != CPU_SCHED_RUNNING) continue;
|
2004-08-06 23:17:59 +00:00
|
|
|
if (leave_apps_in_memory) {
|
|
|
|
if (atp->suspend()) {
|
|
|
|
msg_printf(
|
|
|
|
atp->wup->project,
|
|
|
|
MSG_ERROR,
|
|
|
|
"ACTIVE_TASK_SET::suspend_all(): could not suspend active_task"
|
|
|
|
);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (atp->request_exit()) {
|
|
|
|
msg_printf(
|
|
|
|
atp->wup->project,
|
|
|
|
MSG_ERROR,
|
|
|
|
"ACTIVE_TASK_SET::suspend_all(): could not quit active_task"
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
atp->pending_suspend_via_quit = true;
|
|
|
|
}
|
2003-02-06 19:01:49 +00:00
|
|
|
}
|
2002-04-30 22:22:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-12-06 07:33:45 +00:00
|
|
|
// resume all currently running tasks
|
2002-07-15 23:21:20 +00:00
|
|
|
//
|
2002-04-30 22:22:54 +00:00
|
|
|
void ACTIVE_TASK_SET::unsuspend_all() {
|
|
|
|
unsigned int i;
|
|
|
|
ACTIVE_TASK* atp;
|
2003-02-06 19:01:49 +00:00
|
|
|
for (i=0; i<active_tasks.size(); i++) {
|
2002-04-30 22:22:54 +00:00
|
|
|
atp = active_tasks[i];
|
2004-06-30 01:10:22 +00:00
|
|
|
if (atp->scheduler_state != CPU_SCHED_RUNNING) continue;
|
2004-08-06 23:17:59 +00:00
|
|
|
if (atp->state == PROCESS_UNINITIALIZED) {
|
|
|
|
//atp->pending_suspend_via_quit = false;
|
|
|
|
if (atp->start(false)) {
|
|
|
|
msg_printf(
|
|
|
|
atp->wup->project,
|
|
|
|
MSG_ERROR,
|
|
|
|
"ACTIVE_TASK_SET::unsuspend_all(): could not restart active_task"
|
|
|
|
);
|
|
|
|
}
|
|
|
|
} else if (atp->state == PROCESS_RUNNING && atp->unsuspend()) {
|
2003-06-03 22:47:15 +00:00
|
|
|
msg_printf(
|
2003-03-13 21:49:52 +00:00
|
|
|
atp->wup->project,
|
2003-06-03 22:47:15 +00:00
|
|
|
MSG_ERROR,
|
|
|
|
"ACTIVE_TASK_SET::unsuspend_all(): could not unsuspend active_task"
|
2003-03-13 21:49:52 +00:00
|
|
|
);
|
2003-02-06 19:01:49 +00:00
|
|
|
}
|
2003-07-02 02:02:18 +00:00
|
|
|
}
|
2002-04-30 22:22:54 +00:00
|
|
|
}
|
|
|
|
|
2003-10-18 18:57:34 +00:00
|
|
|
// Send quit signal to all currently running tasks
|
2004-04-03 01:26:40 +00:00
|
|
|
// This is called when the core client exits,
|
|
|
|
// or when a project is detached or reset
|
2002-07-15 23:21:20 +00:00
|
|
|
//
|
2003-10-19 02:54:35 +00:00
|
|
|
void ACTIVE_TASK_SET::request_tasks_exit(PROJECT* proj) {
|
2002-07-01 18:16:31 +00:00
|
|
|
unsigned int i;
|
2002-07-11 01:09:53 +00:00
|
|
|
ACTIVE_TASK *atp;
|
2002-07-01 18:16:31 +00:00
|
|
|
for (i=0; i<active_tasks.size(); i++) {
|
|
|
|
atp = active_tasks[i];
|
2003-10-19 02:54:35 +00:00
|
|
|
if (proj && atp->wup->project != proj) continue;
|
2004-03-30 23:05:34 +00:00
|
|
|
if (atp->state != PROCESS_RUNNING) continue;
|
2003-10-18 18:57:34 +00:00
|
|
|
atp->request_exit();
|
2002-07-01 18:16:31 +00:00
|
|
|
}
|
2002-10-07 06:32:51 +00:00
|
|
|
}
|
2002-10-06 00:43:54 +00:00
|
|
|
|
2003-10-18 18:57:34 +00:00
|
|
|
// Send kill signal to all currently running tasks
|
|
|
|
// Don't wait for them to exit
|
2003-03-11 22:18:01 +00:00
|
|
|
//
|
2003-10-19 02:54:35 +00:00
|
|
|
void ACTIVE_TASK_SET::kill_tasks(PROJECT* proj) {
|
2003-03-11 22:18:01 +00:00
|
|
|
unsigned int i;
|
|
|
|
ACTIVE_TASK *atp;
|
|
|
|
for (i=0; i<active_tasks.size(); i++) {
|
|
|
|
atp = active_tasks[i];
|
2003-10-19 02:54:35 +00:00
|
|
|
if (proj && atp->wup->project != proj) continue;
|
2004-03-30 23:05:34 +00:00
|
|
|
if (atp->state != PROCESS_RUNNING) continue;
|
2003-03-11 22:18:01 +00:00
|
|
|
atp->kill_task();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-12-06 07:33:45 +00:00
|
|
|
// suspend a task
|
2002-07-15 23:21:20 +00:00
|
|
|
//
|
2002-12-06 07:33:45 +00:00
|
|
|
int ACTIVE_TASK::suspend() {
|
2004-07-08 03:38:52 +00:00
|
|
|
app_client_shm.shm->process_control_request.send_msg("<suspend/>");
|
2002-12-06 07:33:45 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2002-06-06 18:42:01 +00:00
|
|
|
|
2002-12-06 07:33:45 +00:00
|
|
|
// resume a suspended task
|
|
|
|
//
|
|
|
|
int ACTIVE_TASK::unsuspend() {
|
2004-07-08 03:38:52 +00:00
|
|
|
app_client_shm.shm->process_control_request.send_msg("<resume/>");
|
2002-12-06 07:33:45 +00:00
|
|
|
return 0;
|
|
|
|
}
|
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) {
|
|
|
|
active_tasks.erase(iter);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
iter++;
|
|
|
|
}
|
2003-07-03 05:01:29 +00:00
|
|
|
msg_printf(NULL, MSG_ERROR, "ACTIVE_TASK_SET::remove(): not found\n");
|
2004-01-30 22:19:19 +00:00
|
|
|
return ERR_NOT_FOUND;
|
2002-04-30 22:22:54 +00:00
|
|
|
}
|
|
|
|
|
2002-07-15 23:21:20 +00:00
|
|
|
// Restart active tasks without wiping and reinitializing slot directories
|
2004-06-30 01:10:22 +00:00
|
|
|
// Called at init, with max_tasks = ncpus
|
2002-07-15 23:21:20 +00:00
|
|
|
//
|
2004-06-30 01:10:22 +00:00
|
|
|
int ACTIVE_TASK_SET::restart_tasks(int max_tasks) {
|
2002-04-30 22:22:54 +00:00
|
|
|
vector<ACTIVE_TASK*>::iterator iter;
|
|
|
|
ACTIVE_TASK* atp;
|
2004-03-24 23:33:46 +00:00
|
|
|
RESULT* result;
|
2004-06-30 01:10:22 +00:00
|
|
|
int retval, num_tasks_started;
|
2002-04-30 22:22:54 +00:00
|
|
|
|
2004-04-08 08:15:23 +00:00
|
|
|
SCOPE_MSG_LOG scope_messages(log_messages, CLIENT_MSG_LOG::DEBUG_TASK);
|
2003-07-02 02:02:18 +00:00
|
|
|
|
2004-06-30 01:10:22 +00:00
|
|
|
num_tasks_started = 0;
|
2002-04-30 22:22:54 +00:00
|
|
|
iter = active_tasks.begin();
|
|
|
|
while (iter != active_tasks.end()) {
|
|
|
|
atp = *iter;
|
2004-03-24 23:33:46 +00:00
|
|
|
result = atp->result;
|
2002-12-11 22:40:33 +00:00
|
|
|
atp->init(atp->result);
|
2002-08-24 00:41:25 +00:00
|
|
|
get_slot_dir(atp->slot, atp->slot_dir);
|
2004-03-24 23:33:46 +00:00
|
|
|
if (!gstate.input_files_available(result)) {
|
|
|
|
msg_printf(atp->wup->project, MSG_ERROR, "ACTIVE_TASKS::restart_tasks(); missing files\n");
|
|
|
|
atp->result->active_task_state = PROCESS_COULDNT_START;
|
|
|
|
gstate.report_result_error(
|
|
|
|
*(atp->result), ERR_FILE_MISSING,
|
|
|
|
"One or more missing files"
|
|
|
|
);
|
2004-03-25 00:10:44 +00:00
|
|
|
iter = active_tasks.erase(iter);
|
2004-03-24 23:33:46 +00:00
|
|
|
delete atp;
|
2004-03-25 00:10:44 +00:00
|
|
|
continue;
|
2004-03-24 23:33:46 +00:00
|
|
|
}
|
2004-06-30 01:10:22 +00:00
|
|
|
|
|
|
|
if (atp->scheduler_state != CPU_SCHED_RUNNING
|
|
|
|
|| num_tasks_started >= max_tasks
|
|
|
|
) {
|
|
|
|
msg_printf(atp->wup->project, MSG_INFO,
|
|
|
|
"Deferring computation for result %s",
|
|
|
|
atp->result->name
|
|
|
|
);
|
|
|
|
|
|
|
|
atp->scheduler_state = CPU_SCHED_PREEMPTED;
|
|
|
|
iter++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2004-03-24 23:33:46 +00:00
|
|
|
result->is_active = true;
|
2004-06-30 01:10:22 +00:00
|
|
|
|
2003-07-29 23:26:32 +00:00
|
|
|
msg_printf(atp->wup->project, MSG_INFO,
|
2004-06-25 22:51:00 +00:00
|
|
|
"Resuming computation for result %s using %s version %.2f",
|
2003-10-22 23:11:49 +00:00
|
|
|
atp->result->name,
|
|
|
|
atp->app_version->app->name,
|
|
|
|
atp->app_version->version_num/100.
|
2003-07-29 23:26:32 +00:00
|
|
|
);
|
2003-10-22 23:11:49 +00:00
|
|
|
retval = atp->start(false);
|
2004-06-30 01:10:22 +00:00
|
|
|
|
2002-04-30 22:22:54 +00:00
|
|
|
if (retval) {
|
2003-06-03 22:47:15 +00:00
|
|
|
msg_printf(atp->wup->project, MSG_ERROR, "ACTIVE_TASKS::restart_tasks(); restart failed: %d\n", retval);
|
2003-01-29 21:40:34 +00:00
|
|
|
atp->result->active_task_state = PROCESS_COULDNT_START;
|
2003-03-13 21:49:52 +00:00
|
|
|
gstate.report_result_error(
|
2003-02-20 00:06:07 +00:00
|
|
|
*(atp->result), retval,
|
2003-10-30 20:00:30 +00:00
|
|
|
"Couldn't restart the app for this result: %d", retval
|
2003-02-20 00:06:07 +00:00
|
|
|
);
|
2004-03-25 00:10:44 +00:00
|
|
|
iter = active_tasks.erase(iter);
|
2004-03-24 23:33:46 +00:00
|
|
|
delete atp;
|
2002-04-30 22:22:54 +00:00
|
|
|
} else {
|
2004-06-30 01:10:22 +00:00
|
|
|
++num_tasks_started;
|
2002-04-30 22:22:54 +00:00
|
|
|
iter++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2003-11-25 17:17:21 +00:00
|
|
|
// compute frac_rate_of_change
|
|
|
|
//
|
|
|
|
void ACTIVE_TASK::estimate_frac_rate_of_change(double now) {
|
|
|
|
if (last_frac_update == 0) {
|
|
|
|
last_frac_update = now;
|
|
|
|
last_frac_done = fraction_done;
|
|
|
|
recent_change = 0;
|
|
|
|
} else {
|
|
|
|
recent_change += (fraction_done - last_frac_done);
|
|
|
|
int tdiff = (int)(now-last_frac_update);
|
|
|
|
if (tdiff>0) {
|
|
|
|
double recent_frac_rate_of_change = max(0.0, recent_change) / tdiff;
|
|
|
|
if (frac_rate_of_change == 0) {
|
|
|
|
frac_rate_of_change = recent_frac_rate_of_change;
|
|
|
|
} else {
|
|
|
|
double x = exp(-1*log(2.0)/20.0);
|
|
|
|
frac_rate_of_change = frac_rate_of_change*x + recent_frac_rate_of_change*(1-x);
|
|
|
|
}
|
|
|
|
last_frac_update = now;
|
|
|
|
last_frac_done = fraction_done;
|
|
|
|
recent_change = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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);
|
2004-06-29 23:31:51 +00:00
|
|
|
sprintf(old_path, "%s%strickle_up.xml", slot_dir, PATH_SEPARATOR);
|
2004-01-04 06:48:40 +00:00
|
|
|
sprintf(new_path,
|
2004-06-29 23:31:51 +00:00
|
|
|
"%s%strickle_up_%s_%d.xml",
|
2004-01-04 06:48:40 +00:00
|
|
|
project_dir, PATH_SEPARATOR, result->name, (int)time(0)
|
|
|
|
);
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2003-11-25 17:17:21 +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.
|
2002-07-15 23:21:20 +00:00
|
|
|
//
|
2004-08-03 09:50:24 +00:00
|
|
|
bool ACTIVE_TASK::get_msg() {
|
2004-07-08 03:38:52 +00:00
|
|
|
char msg_buf[MSG_CHANNEL_SIZE];
|
2004-08-03 09:50:24 +00:00
|
|
|
bool found = false;
|
|
|
|
int retval;
|
|
|
|
|
2004-07-08 03:38:52 +00:00
|
|
|
if (app_client_shm.shm->app_status.get_msg(msg_buf)) {
|
2003-05-08 18:11:05 +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);
|
2004-07-26 22:23:16 +00:00
|
|
|
parse_double(msg_buf, "<vm_size>", vm_size);
|
|
|
|
parse_double(msg_buf, "<resident_set_size>", resident_set_size);
|
2004-08-03 09:50:24 +00:00
|
|
|
found = true;
|
|
|
|
}
|
|
|
|
if (app_client_shm.shm->trickle_up.get_msg(msg_buf)) {
|
2004-07-06 04:01:15 +00:00
|
|
|
if (match_tag(msg_buf, "<have_new_trickle_up/>")) {
|
2004-08-03 09:50:24 +00:00
|
|
|
retval = move_trickle_file();
|
|
|
|
if (!retval) {
|
|
|
|
wup->project->sched_rpc_pending = true;
|
|
|
|
}
|
2004-01-04 06:48:40 +00:00
|
|
|
}
|
2004-08-03 09:50:24 +00:00
|
|
|
found = true;
|
2002-08-05 00:29:34 +00:00
|
|
|
}
|
2004-08-03 09:50:24 +00:00
|
|
|
return found;
|
2003-03-17 19:24:38 +00:00
|
|
|
}
|
|
|
|
|
2004-08-03 09:50:24 +00:00
|
|
|
// check for msgs from active tasks.
|
2003-11-25 17:17:21 +00:00
|
|
|
// Return true if any of them has changed its checkpoint_cpu_time
|
|
|
|
// (since in that case we need to write state file)
|
2003-03-17 19:24:38 +00:00
|
|
|
//
|
2004-08-03 09:50:24 +00:00
|
|
|
bool ACTIVE_TASK_SET::get_msgs() {
|
2003-03-17 19:24:38 +00:00
|
|
|
unsigned int i;
|
|
|
|
ACTIVE_TASK *atp;
|
2003-11-25 17:17:21 +00:00
|
|
|
double now = dtime(), old_time;
|
|
|
|
bool action = false;
|
|
|
|
|
2003-03-17 19:24:38 +00:00
|
|
|
for (i=0; i<active_tasks.size(); i++) {
|
|
|
|
atp = active_tasks[i];
|
2004-07-09 18:24:08 +00:00
|
|
|
if (atp->state == PROCESS_IN_LIMBO
|
|
|
|
|| atp->state == PROCESS_UNINITIALIZED
|
|
|
|
) {
|
|
|
|
continue;
|
|
|
|
}
|
2003-11-25 17:17:21 +00:00
|
|
|
old_time = atp->checkpoint_cpu_time;
|
2004-08-03 09:50:24 +00:00
|
|
|
if (atp->get_msg()) {
|
2003-11-25 17:17:21 +00:00
|
|
|
atp->estimate_frac_rate_of_change(now);
|
|
|
|
if (old_time != atp->checkpoint_cpu_time) {
|
|
|
|
action = true;
|
|
|
|
}
|
|
|
|
}
|
2003-03-17 19:24:38 +00:00
|
|
|
}
|
2003-11-25 17:17:21 +00:00
|
|
|
return action;
|
2002-06-21 18:31:32 +00:00
|
|
|
}
|
|
|
|
|
2002-12-06 07:33:45 +00:00
|
|
|
// Returns the estimated time to completion (in seconds) of this task,
|
|
|
|
// based on current reported CPU time and fraction done
|
2002-11-20 20:14:48 +00:00
|
|
|
//
|
|
|
|
double ACTIVE_TASK::est_time_to_completion() {
|
2003-08-13 20:00:19 +00:00
|
|
|
if (fraction_done <= 0 || fraction_done > 1 || frac_rate_of_change <= 0) {
|
2002-12-05 21:56:33 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2003-08-13 21:32:07 +00:00
|
|
|
return (current_cpu_time / fraction_done) - current_cpu_time;
|
|
|
|
//return (1.0-fraction_done)/frac_rate_of_change;
|
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
|
|
|
}
|
2004-06-30 01:10:22 +00:00
|
|
|
return -1; // probably never get here
|
2002-08-26 22:14:06 +00:00
|
|
|
}
|
|
|
|
|
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"
|
|
|
|
" <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"
|
2002-04-30 22:22:54 +00:00
|
|
|
"</active_task>\n",
|
2002-06-21 06:52:47 +00:00
|
|
|
result->project->master_url,
|
2002-04-30 22:22:54 +00:00
|
|
|
result->name,
|
|
|
|
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,
|
|
|
|
current_cpu_time
|
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];
|
2002-04-30 22:22:54 +00:00
|
|
|
int app_version_num=0;
|
|
|
|
PROJECT* project;
|
2002-08-05 00:29:34 +00:00
|
|
|
|
2004-05-18 22:47:08 +00:00
|
|
|
SCOPE_MSG_LOG scope_messages(log_messages, CLIENT_MSG_LOG::DEBUG_TASK);
|
|
|
|
|
2003-03-19 01:15:46 +00:00
|
|
|
strcpy(result_name, "");
|
|
|
|
strcpy(project_master_url, "");
|
2004-07-08 17:59:46 +00:00
|
|
|
scheduler_state = CPU_SCHED_RUNNING;
|
|
|
|
|
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,
|
2002-04-30 22:22:54 +00:00
|
|
|
"ACTIVE_TASK::parse(): project not found: %s\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(
|
2003-11-06 00:00:00 +00:00
|
|
|
project, MSG_ERROR, "ACTIVE_TASK::parse(): result not found\n"
|
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,
|
|
|
|
"ACTIVE_TASK::parse(): result is in wrong state\n"
|
|
|
|
);
|
|
|
|
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,
|
2003-07-03 05:01:29 +00:00
|
|
|
"ACTIVE_TASK::parse(): app_version not found\n"
|
|
|
|
);
|
2003-11-06 00:00:00 +00:00
|
|
|
return ERR_NULL;
|
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;
|
2004-06-30 01:10:22 +00:00
|
|
|
else if (parse_int(buf, "<scheduler_state>", scheduler_state)) 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;
|
2004-05-18 22:47:08 +00:00
|
|
|
else scope_messages.printf("ACTIVE_TASK::parse(): unrecognized %s\n", buf);
|
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-05-18 22:47:08 +00:00
|
|
|
SCOPE_MSG_LOG scope_messages(log_messages, CLIENT_MSG_LOG::DEBUG_TASK);
|
|
|
|
|
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);
|
2002-04-30 22:22:54 +00:00
|
|
|
if (!retval) active_tasks.push_back(atp);
|
|
|
|
else delete atp;
|
2004-05-18 22:47:08 +00:00
|
|
|
} else scope_messages.printf("ACTIVE_TASK_SET::parse(): unrecognized %s\n", buf);
|
2002-04-30 22:22:54 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2003-05-08 18:11:05 +00:00
|
|
|
|
2004-07-18 04:41:27 +00:00
|
|
|
////// GRAPHICS STUFF STARTS HERE ///////////////
|
|
|
|
|
|
|
|
void ACTIVE_TASK::request_graphics_mode(int mode) {
|
|
|
|
graphics_mode_requested = mode;
|
|
|
|
graphics_mode_sent = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ACTIVE_TASK::send_graphics_mode(int mode) {
|
|
|
|
bool sent = app_client_shm.shm->graphics_request.send_msg(
|
|
|
|
xml_graphics_modes[mode]
|
|
|
|
);
|
|
|
|
//msg_printf(NULL, MSG_INFO, "%d requested mode %d: sent %d", time(0), mode, sent);
|
|
|
|
return sent;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ACTIVE_TASK::check_graphics_mode_ack() {
|
|
|
|
int mode;
|
|
|
|
char buf[MSG_CHANNEL_SIZE];
|
|
|
|
if (app_client_shm.shm->graphics_reply.get_msg(buf)) {
|
|
|
|
mode = app_client_shm.decode_graphics_msg(buf);
|
2004-07-18 05:30:26 +00:00
|
|
|
//msg_printf(NULL, MSG_INFO, "got graphics ack %d", mode);
|
2004-07-18 04:41:27 +00:00
|
|
|
if (mode != MODE_REREAD_PREFS) {
|
|
|
|
graphics_mode_acked = mode;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
2003-05-08 18:11:05 +00:00
|
|
|
// return an app with pre-ss mode WINDOW, if there is one
|
|
|
|
// else return an app with pre-ss mode HIDE, if there is one
|
|
|
|
// else return NULL
|
|
|
|
//
|
|
|
|
ACTIVE_TASK* ACTIVE_TASK_SET::get_graphics_capable_app() {
|
|
|
|
unsigned int i;
|
|
|
|
ACTIVE_TASK* atp;
|
|
|
|
|
|
|
|
for (i=0; i<active_tasks.size(); i++) {
|
|
|
|
atp = active_tasks[i];
|
2004-06-30 01:10:22 +00:00
|
|
|
if (atp->scheduler_state != CPU_SCHED_RUNNING) continue;
|
2003-05-08 18:11:05 +00:00
|
|
|
if (atp->graphics_mode_before_ss == MODE_WINDOW) {
|
|
|
|
return atp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (i=0; i<active_tasks.size(); i++) {
|
|
|
|
atp = active_tasks[i];
|
2004-06-30 01:10:22 +00:00
|
|
|
if (atp->scheduler_state != CPU_SCHED_RUNNING) continue;
|
2003-05-08 18:11:05 +00:00
|
|
|
if (atp->graphics_mode_before_ss == MODE_HIDE_GRAPHICS) {
|
|
|
|
return atp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
2004-07-18 04:41:27 +00:00
|
|
|
#endif
|
2003-05-08 18:11:05 +00:00
|
|
|
|
|
|
|
// return an app (if any) with given requested mode
|
|
|
|
//
|
2004-07-18 04:41:27 +00:00
|
|
|
ACTIVE_TASK* ACTIVE_TASK_SET::get_app_graphics_mode_requested(int req_mode) {
|
2003-05-08 18:11:05 +00:00
|
|
|
unsigned int i;
|
|
|
|
ACTIVE_TASK* atp;
|
|
|
|
|
|
|
|
for (i=0; i<active_tasks.size(); i++) {
|
|
|
|
atp = active_tasks[i];
|
2004-06-30 01:10:22 +00:00
|
|
|
if (atp->scheduler_state != CPU_SCHED_RUNNING) continue;
|
2004-07-18 04:41:27 +00:00
|
|
|
if (atp->graphics_mode_requested == req_mode) {
|
2003-05-08 18:11:05 +00:00
|
|
|
return atp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ACTIVE_TASK_SET::save_app_modes() {
|
|
|
|
unsigned int i;
|
|
|
|
ACTIVE_TASK* atp;
|
|
|
|
|
|
|
|
for (i=0; i<active_tasks.size(); i++) {
|
|
|
|
atp = active_tasks[i];
|
2004-06-30 01:10:22 +00:00
|
|
|
if (atp->scheduler_state != CPU_SCHED_RUNNING) continue;
|
2004-07-18 04:41:27 +00:00
|
|
|
atp->graphics_mode_before_ss = atp->graphics_mode_acked;
|
2004-07-18 05:30:26 +00:00
|
|
|
//msg_printf(NULL, MSG_INFO, "saved mode %d", atp->graphics_mode_acked);
|
2003-05-08 18:11:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ACTIVE_TASK_SET::hide_apps() {
|
|
|
|
unsigned int i;
|
|
|
|
ACTIVE_TASK* atp;
|
|
|
|
|
|
|
|
for (i=0; i<active_tasks.size(); i++) {
|
|
|
|
atp = active_tasks[i];
|
2004-06-30 01:10:22 +00:00
|
|
|
if (atp->scheduler_state != CPU_SCHED_RUNNING) continue;
|
2003-05-09 18:17:25 +00:00
|
|
|
atp->request_graphics_mode(MODE_HIDE_GRAPHICS);
|
2003-05-08 18:11:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-07-18 04:41:27 +00:00
|
|
|
// return apps to the mode they were in before screensaving started
|
|
|
|
//
|
2003-05-08 18:11:05 +00:00
|
|
|
void ACTIVE_TASK_SET::restore_apps() {
|
|
|
|
unsigned int i;
|
|
|
|
ACTIVE_TASK* atp;
|
|
|
|
|
|
|
|
for (i=0; i<active_tasks.size(); i++) {
|
|
|
|
atp = active_tasks[i];
|
2004-06-30 01:10:22 +00:00
|
|
|
if (atp->scheduler_state != CPU_SCHED_RUNNING) continue;
|
2004-07-18 04:41:27 +00:00
|
|
|
if (atp->graphics_mode_requested != atp->graphics_mode_before_ss) {
|
2003-05-09 18:17:25 +00:00
|
|
|
atp->request_graphics_mode(atp->graphics_mode_before_ss);
|
2003-05-08 18:11:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2003-05-09 00:00:39 +00:00
|
|
|
|
2004-07-18 04:41:27 +00:00
|
|
|
void ACTIVE_TASK_SET::graphics_poll() {
|
2003-05-09 00:00:39 +00:00
|
|
|
unsigned int i;
|
|
|
|
ACTIVE_TASK* atp;
|
2004-07-18 04:41:27 +00:00
|
|
|
bool sent;
|
2003-05-09 00:00:39 +00:00
|
|
|
|
|
|
|
for (i=0; i<active_tasks.size(); i++) {
|
|
|
|
atp = active_tasks[i];
|
2004-08-06 23:17:59 +00:00
|
|
|
if (atp->scheduler_state != CPU_SCHED_RUNNING ||
|
|
|
|
atp->state != PROCESS_RUNNING
|
|
|
|
) continue;
|
2004-07-18 04:41:27 +00:00
|
|
|
if (atp->graphics_mode_requested != atp->graphics_mode_sent) {
|
|
|
|
sent = atp->send_graphics_mode(atp->graphics_mode_requested);
|
|
|
|
if (sent) {
|
|
|
|
atp->graphics_mode_sent = atp->graphics_mode_requested;
|
|
|
|
}
|
|
|
|
//msg_printf(NULL, MSG_INFO, "sending graphics req %d: %d", sent);
|
|
|
|
}
|
2003-05-09 20:33:57 +00:00
|
|
|
atp->check_graphics_mode_ack();
|
|
|
|
}
|
2003-05-09 00:00:39 +00:00
|
|
|
}
|
2003-05-29 18:28:02 +00:00
|
|
|
|
|
|
|
bool ACTIVE_TASK::supports_graphics() {
|
2004-07-18 04:41:27 +00:00
|
|
|
return (graphics_mode_acked != MODE_UNSUPPORTED);
|
2003-05-29 18:28:02 +00:00
|
|
|
}
|
2004-06-30 01:10:22 +00:00
|
|
|
|