2005-01-20 23:22:22 +00:00
|
|
|
// Berkeley Open Infrastructure for Network Computing
|
|
|
|
// http://boinc.berkeley.edu
|
|
|
|
// Copyright (C) 2005 University of California
|
2004-08-11 11:30:25 +00:00
|
|
|
//
|
2005-01-20 23:22:22 +00:00
|
|
|
// This is free software; you can redistribute it and/or
|
|
|
|
// modify it under the terms of the GNU Lesser General Public
|
|
|
|
// License as published by the Free Software Foundation;
|
|
|
|
// either version 2.1 of the License, or (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This software is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
// See the GNU Lesser General Public License for more details.
|
|
|
|
//
|
|
|
|
// To view the GNU Lesser General Public License visit
|
|
|
|
// http://www.gnu.org/copyleft/lesser.html
|
|
|
|
// or write to the Free Software Foundation, Inc.,
|
|
|
|
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
2004-08-11 11:30:25 +00:00
|
|
|
|
|
|
|
// initialization and starting of applications
|
|
|
|
|
|
|
|
#include "cpp.h"
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
#include "boinc_win.h"
|
|
|
|
#else
|
2005-11-21 18:34:44 +00:00
|
|
|
#include "config.h"
|
2004-08-16 11:31:59 +00:00
|
|
|
#if HAVE_SYS_TIME_H
|
|
|
|
#include <sys/time.h>
|
2004-08-11 11:30:25 +00:00
|
|
|
#endif
|
2004-08-11 15:27:46 +00:00
|
|
|
#if HAVE_SYS_RESOURCE_H
|
|
|
|
#include <sys/resource.h>
|
|
|
|
#endif
|
2004-08-16 11:31:59 +00:00
|
|
|
#if HAVE_SYS_IPC_H
|
|
|
|
#include <sys/ipc.h>
|
|
|
|
#endif
|
2004-08-11 15:27:46 +00:00
|
|
|
#if HAVE_SYS_WAIT_H
|
|
|
|
#include <sys/wait.h>
|
|
|
|
#endif
|
2004-08-11 11:30:25 +00:00
|
|
|
#include <unistd.h>
|
2004-08-12 13:02:25 +00:00
|
|
|
#include <cerrno>
|
2004-08-11 11:30:25 +00:00
|
|
|
#endif
|
|
|
|
|
2005-12-02 22:29:35 +00:00
|
|
|
#ifdef __EMX__
|
|
|
|
#include <process.h>
|
|
|
|
#endif
|
|
|
|
|
2006-02-06 23:44:05 +00:00
|
|
|
#if (defined(__APPLE__) && defined(__i386__))
|
|
|
|
#include <mach-o/loader.h>
|
|
|
|
#include <mach-o/fat.h>
|
|
|
|
#include <mach/machine.h>
|
|
|
|
#include <libkern/OSByteOrder.h>
|
|
|
|
#endif
|
|
|
|
|
2004-08-11 11:30:25 +00:00
|
|
|
using std::vector;
|
|
|
|
|
|
|
|
#include "filesys.h"
|
|
|
|
#include "error_numbers.h"
|
|
|
|
#include "util.h"
|
|
|
|
#include "shmem.h"
|
|
|
|
#include "client_msgs.h"
|
|
|
|
#include "client_state.h"
|
|
|
|
#include "file_names.h"
|
2006-05-21 22:03:36 +00:00
|
|
|
#include "log_flags.h"
|
2004-08-11 11:30:25 +00:00
|
|
|
|
|
|
|
#include "app.h"
|
|
|
|
|
|
|
|
// value for setpriority(2)
|
|
|
|
static const int PROCESS_IDLE_PRIORITY = 19;
|
|
|
|
|
|
|
|
// Goes through an array of strings, and prints each string
|
|
|
|
//
|
|
|
|
static int debug_print_argv(char** argv) {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
log_messages.printf(CLIENT_MSG_LOG::DEBUG_TASK, "Arguments:");
|
|
|
|
++log_messages;
|
|
|
|
for (i=0; argv[i]; i++) {
|
|
|
|
log_messages.printf(
|
|
|
|
CLIENT_MSG_LOG::DEBUG_TASK,
|
|
|
|
"argv[%d]: %s\n", i, argv[i]
|
|
|
|
);
|
|
|
|
}
|
|
|
|
--log_messages;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2006-03-03 21:34:03 +00:00
|
|
|
sprintf(link_path, "%s/%s", slot_dir, strlen(fref.open_name)?fref.open_name:fip->name);
|
|
|
|
sprintf(buf, "../../%s", file_path);
|
2004-08-11 11:30:25 +00:00
|
|
|
retval = boinc_link(buf, link_path);
|
|
|
|
if (retval) return retval;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-08-31 21:02:17 +00:00
|
|
|
// make a unique key for core/app shared memory segment
|
|
|
|
//
|
|
|
|
int ACTIVE_TASK::get_shmem_seg_name() {
|
|
|
|
#ifdef _WIN32
|
|
|
|
int i = 0;
|
|
|
|
char szSharedMemoryName[256];
|
|
|
|
HANDLE hSharedMemoryHandle = 0;
|
|
|
|
|
|
|
|
for (i=0; i<1024; i++) {
|
2004-09-01 04:59:32 +00:00
|
|
|
sprintf(szSharedMemoryName, "%sboinc_%d", SHM_PREFIX, i);
|
|
|
|
hSharedMemoryHandle = create_shmem(szSharedMemoryName, 1024, NULL, true);
|
2004-08-31 21:02:17 +00:00
|
|
|
if (hSharedMemoryHandle) break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!hSharedMemoryHandle) {
|
|
|
|
return ERR_SHMGET;
|
|
|
|
}
|
2004-09-01 04:59:32 +00:00
|
|
|
detach_shmem(hSharedMemoryHandle, NULL);
|
|
|
|
|
|
|
|
sprintf(szSharedMemoryName, "boinc_%d", i);
|
2004-08-31 21:02:17 +00:00
|
|
|
strcpy(shmem_seg_name, szSharedMemoryName);
|
|
|
|
|
2004-11-02 23:12:29 +00:00
|
|
|
#else
|
2004-08-31 21:02:17 +00:00
|
|
|
char init_data_path[256];
|
2006-03-03 21:34:03 +00:00
|
|
|
sprintf(init_data_path, "%s/%s", slot_dir, INIT_DATA_FILE);
|
2005-06-25 05:26:54 +00:00
|
|
|
|
|
|
|
// ftok() only works if there's a file at the given location
|
|
|
|
//
|
|
|
|
FILE* f = boinc_fopen(init_data_path, "w");
|
|
|
|
if (f) fclose(f);
|
2004-08-31 21:02:17 +00:00
|
|
|
shmem_seg_name = ftok(init_data_path, slot);
|
2005-06-24 08:12:11 +00:00
|
|
|
if (shmem_seg_name == -1) return ERR_SHMEM_NAME;
|
2004-08-31 21:02:17 +00:00
|
|
|
#endif
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-08-11 11:30:25 +00:00
|
|
|
// write the app init file.
|
|
|
|
// This is done before starting the app,
|
|
|
|
// and when project prefs have changed during app execution
|
|
|
|
//
|
2004-08-31 21:02:17 +00:00
|
|
|
int ACTIVE_TASK::write_app_init_file() {
|
|
|
|
APP_INIT_DATA aid;
|
2004-08-11 11:30:25 +00:00
|
|
|
FILE *f;
|
|
|
|
char init_data_path[256], project_dir[256], project_path[256];
|
|
|
|
int retval;
|
|
|
|
|
|
|
|
memset(&aid, 0, sizeof(aid));
|
|
|
|
|
2005-08-31 00:18:36 +00:00
|
|
|
aid.major_version = BOINC_MAJOR_VERSION;
|
|
|
|
aid.minor_version = BOINC_MINOR_VERSION;
|
|
|
|
aid.release = BOINC_RELEASE;
|
2005-10-12 18:40:53 +00:00
|
|
|
aid.app_version = app_version->version_num;
|
2004-08-11 11:30:25 +00:00
|
|
|
safe_strcpy(aid.app_name, wup->app->name);
|
2006-05-22 09:54:31 +00:00
|
|
|
safe_strcpy(aid.symstore, wup->project->symstore);
|
2004-08-11 11:30:25 +00:00
|
|
|
safe_strcpy(aid.user_name, wup->project->user_name);
|
|
|
|
safe_strcpy(aid.team_name, wup->project->team_name);
|
|
|
|
if (wup->project->project_specific_prefs.length()) {
|
2005-02-18 23:43:28 +00:00
|
|
|
aid.project_preferences = strdup(wup->project->project_specific_prefs.c_str());
|
2004-08-11 11:30:25 +00:00
|
|
|
}
|
|
|
|
get_project_dir(wup->project, project_dir);
|
|
|
|
relative_to_absolute(project_dir, project_path);
|
|
|
|
strcpy(aid.project_dir, project_path);
|
|
|
|
relative_to_absolute("", aid.boinc_dir);
|
|
|
|
strcpy(aid.authenticator, wup->project->authenticator);
|
|
|
|
aid.slot = slot;
|
|
|
|
strcpy(aid.wu_name, wup->name);
|
|
|
|
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;
|
|
|
|
aid.checkpoint_period = gstate.global_prefs.disk_interval;
|
|
|
|
aid.fraction_done_update_period = DEFAULT_FRACTION_DONE_UPDATE_PERIOD;
|
|
|
|
aid.fraction_done_start = 0;
|
|
|
|
aid.fraction_done_end = 1;
|
2004-08-31 21:02:17 +00:00
|
|
|
#ifdef _WIN32
|
|
|
|
strcpy(aid.shmem_seg_name, shmem_seg_name);
|
|
|
|
#else
|
|
|
|
aid.shmem_seg_name = shmem_seg_name;
|
2004-08-11 11:30:25 +00:00
|
|
|
#endif
|
|
|
|
// 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;
|
|
|
|
|
2006-03-03 21:34:03 +00:00
|
|
|
sprintf(init_data_path, "%s/%s", slot_dir, INIT_DATA_FILE);
|
2004-08-11 11:30:25 +00:00
|
|
|
f = boinc_fopen(init_data_path, "w");
|
|
|
|
if (!f) {
|
|
|
|
msg_printf(wup->project, MSG_ERROR,
|
2006-01-17 22:48:09 +00:00
|
|
|
"Failed to open init file %s",
|
2004-08-11 11:30:25 +00:00
|
|
|
init_data_path
|
|
|
|
);
|
|
|
|
return ERR_FOPEN;
|
|
|
|
}
|
|
|
|
|
|
|
|
aid.host_info = gstate.host_info;
|
2004-10-06 19:09:37 +00:00
|
|
|
aid.global_prefs = gstate.global_prefs;
|
2005-02-19 00:14:16 +00:00
|
|
|
aid.proxy_info = gstate.proxy_info;
|
2004-08-11 11:30:25 +00:00
|
|
|
retval = write_init_data_file(f, aid);
|
|
|
|
fclose(f);
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2004-08-11 12:15:31 +00:00
|
|
|
// set up a 'symbolic link' in the slot dir to the given file
|
|
|
|
// (or copy the file to slot dir)
|
|
|
|
//
|
|
|
|
static int setup_file(
|
|
|
|
WORKUNIT* wup, FILE_INFO* fip, FILE_REF& fref,
|
|
|
|
char* file_path, char* slot_dir
|
|
|
|
) {
|
|
|
|
char link_path[256], buf[256];
|
|
|
|
int retval;
|
|
|
|
|
|
|
|
sprintf(link_path,
|
2006-03-03 21:34:03 +00:00
|
|
|
"%s/%s",
|
|
|
|
slot_dir, strlen(fref.open_name)?fref.open_name:fip->name
|
2004-08-11 12:15:31 +00:00
|
|
|
);
|
2006-03-03 21:34:03 +00:00
|
|
|
sprintf(buf, "../../%s", file_path );
|
2004-08-11 12:15:31 +00:00
|
|
|
if (fref.copy_file) {
|
|
|
|
retval = boinc_copy(file_path, link_path);
|
|
|
|
if (retval) {
|
2006-01-17 22:48:09 +00:00
|
|
|
msg_printf(wup->project, MSG_ERROR,
|
|
|
|
"Can't copy %s to %s", file_path, link_path
|
|
|
|
);
|
2004-08-11 12:15:31 +00:00
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
} else {
|
2005-09-08 17:13:31 +00:00
|
|
|
// if anonymous platform, link may already be there
|
|
|
|
//
|
2005-09-07 00:03:43 +00:00
|
|
|
if (wup->project->anonymous_platform && boinc_file_exists(link_path)) {
|
2005-09-06 23:40:26 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2004-08-11 12:15:31 +00:00
|
|
|
retval = boinc_link(buf, link_path);
|
|
|
|
if (retval) {
|
2006-01-17 22:48:09 +00:00
|
|
|
msg_printf(wup->project, MSG_ERROR,
|
|
|
|
"Can't link %s to %s", file_path, link_path
|
|
|
|
);
|
2004-08-11 12:15:31 +00:00
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-08-11 11:30:25 +00:00
|
|
|
// 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
|
|
|
|
//
|
2005-01-21 23:26:36 +00:00
|
|
|
// postcondition: ACTIVE_TASK::task_state is set correctly
|
2004-10-07 19:18:37 +00:00
|
|
|
//
|
2004-08-11 11:30:25 +00:00
|
|
|
int ACTIVE_TASK::start(bool first_time) {
|
2004-08-11 12:15:31 +00:00
|
|
|
char exec_name[256], file_path[256], buf[256], exec_path[256];
|
2004-08-11 11:30:25 +00:00
|
|
|
unsigned int i;
|
2004-08-11 12:15:31 +00:00
|
|
|
FILE_REF fref;
|
2004-08-11 11:30:25 +00:00
|
|
|
FILE_INFO* fip;
|
|
|
|
int retval;
|
|
|
|
|
|
|
|
SCOPE_MSG_LOG scope_messages(log_messages, CLIENT_MSG_LOG::DEBUG_TASK);
|
|
|
|
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;
|
|
|
|
episode_start_cpu_time = checkpoint_cpu_time;
|
|
|
|
cpu_time_at_last_sched = checkpoint_cpu_time;
|
|
|
|
|
2004-08-31 21:02:17 +00:00
|
|
|
if (!app_client_shm.shm) {
|
|
|
|
retval = get_shmem_seg_name();
|
|
|
|
if (retval) {
|
|
|
|
msg_printf(wup->project, MSG_ERROR,
|
2005-07-05 09:02:55 +00:00
|
|
|
"Can't get shared memory segment name: %s", boincerror(retval)
|
2004-08-31 21:02:17 +00:00
|
|
|
);
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
}
|
2004-09-01 04:59:32 +00:00
|
|
|
|
2005-06-25 05:26:54 +00:00
|
|
|
// this must go AFTER creating shmem,
|
|
|
|
// since the shmem name is part of the file
|
|
|
|
//
|
|
|
|
retval = write_app_init_file();
|
|
|
|
if (retval) return retval;
|
|
|
|
|
2004-08-11 12:15:31 +00:00
|
|
|
// set up applications files
|
2004-08-11 11:30:25 +00:00
|
|
|
//
|
2005-02-11 18:26:59 +00:00
|
|
|
strcpy(exec_name, "");
|
2004-08-11 11:30:25 +00:00
|
|
|
for (i=0; i<app_version->app_files.size(); i++) {
|
2005-02-18 23:50:38 +00:00
|
|
|
fref = app_version->app_files[i];
|
2004-08-11 11:30:25 +00:00
|
|
|
fip = fref.file_info;
|
|
|
|
get_pathname(fip, file_path);
|
|
|
|
if (fref.main_program) {
|
2005-04-06 19:41:31 +00:00
|
|
|
if (is_image_file(fip->name)) {
|
|
|
|
msg_printf(wup->project, MSG_ERROR,
|
|
|
|
"Main program %s is an image file", fip->name
|
|
|
|
);
|
|
|
|
return ERR_NO_SIGNATURE;
|
|
|
|
}
|
2005-03-08 00:23:58 +00:00
|
|
|
if (!fip->executable && !wup->project->anonymous_platform) {
|
2005-02-11 18:26:59 +00:00
|
|
|
msg_printf(wup->project, MSG_ERROR,
|
|
|
|
"Main program %s is not executable", fip->name
|
|
|
|
);
|
|
|
|
return ERR_NO_SIGNATURE;
|
|
|
|
}
|
2004-08-11 11:30:25 +00:00
|
|
|
safe_strcpy(exec_name, fip->name);
|
|
|
|
safe_strcpy(exec_path, file_path);
|
|
|
|
}
|
2005-09-08 17:13:31 +00:00
|
|
|
// anonymous platform may use different files than
|
|
|
|
// when the result was started
|
|
|
|
//
|
2005-09-06 12:58:56 +00:00
|
|
|
if (first_time || wup->project->anonymous_platform) {
|
2004-08-11 12:15:31 +00:00
|
|
|
retval = setup_file(wup, fip, fref, file_path, slot_dir);
|
|
|
|
if (retval) return retval;
|
2004-08-11 11:30:25 +00:00
|
|
|
}
|
|
|
|
}
|
2005-02-11 18:26:59 +00:00
|
|
|
if (!strlen(exec_name)) {
|
|
|
|
msg_printf(wup->project, MSG_ERROR,
|
|
|
|
"No main program specified"
|
|
|
|
);
|
|
|
|
return ERR_NOT_FOUND;
|
|
|
|
}
|
2004-08-11 11:30:25 +00:00
|
|
|
|
2006-04-28 17:23:00 +00:00
|
|
|
// set up input, output files
|
2004-08-11 11:30:25 +00:00
|
|
|
//
|
2006-04-28 17:23:00 +00:00
|
|
|
if (first_time) {
|
|
|
|
for (i=0; i<wup->input_files.size(); i++) {
|
|
|
|
fref = wup->input_files[i];
|
|
|
|
fip = fref.file_info;
|
|
|
|
get_pathname(fref.file_info, file_path);
|
2004-08-11 12:15:31 +00:00
|
|
|
retval = setup_file(wup, fip, fref, file_path, slot_dir);
|
2004-08-11 11:30:25 +00:00
|
|
|
if (retval) return retval;
|
|
|
|
}
|
2006-04-28 17:23:00 +00:00
|
|
|
for (i=0; i<result->output_files.size(); i++) {
|
|
|
|
fref = result->output_files[i];
|
|
|
|
fip = fref.file_info;
|
|
|
|
get_pathname(fref.file_info, file_path);
|
2004-08-11 12:15:31 +00:00
|
|
|
retval = setup_file(wup, fip, fref, file_path, slot_dir);
|
2004-08-11 11:30:25 +00:00
|
|
|
if (retval) return retval;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
link_user_files();
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
PROCESS_INFORMATION process_info;
|
|
|
|
STARTUPINFO startup_info;
|
|
|
|
char slotdirpath[256];
|
2004-12-26 02:55:31 +00:00
|
|
|
std::string cmd_line;
|
2005-02-17 21:18:17 +00:00
|
|
|
char error_msg[1024];
|
2004-08-11 11:30:25 +00:00
|
|
|
|
|
|
|
memset(&process_info, 0, sizeof(process_info));
|
|
|
|
memset(&startup_info, 0, sizeof(startup_info));
|
2004-11-21 04:18:26 +00:00
|
|
|
//startup_info.cb = sizeof(startup_info);
|
|
|
|
//startup_info.dwFlags = STARTF_USESHOWWINDOW;
|
|
|
|
//startup_info.wShowWindow = SW_HIDE;
|
2004-08-11 11:30:25 +00:00
|
|
|
|
2004-09-01 04:59:32 +00:00
|
|
|
if (!quitRequestEvent) {
|
|
|
|
sprintf(buf, "%s%s", QUIT_PREFIX, shmem_seg_name);
|
|
|
|
quitRequestEvent = CreateEvent(0, FALSE, FALSE, buf);
|
|
|
|
if (quitRequestEvent == NULL) return ERR_INVALID_EVENT;
|
|
|
|
}
|
2004-08-11 11:30:25 +00:00
|
|
|
|
2004-08-31 21:02:17 +00:00
|
|
|
// create core/app share mem segment if needed
|
2004-08-11 11:30:25 +00:00
|
|
|
//
|
2004-08-31 21:20:31 +00:00
|
|
|
if (!app_client_shm.shm) {
|
2004-08-31 21:02:17 +00:00
|
|
|
sprintf(buf, "%s%s", SHM_PREFIX, shmem_seg_name);
|
|
|
|
shm_handle = create_shmem(buf, sizeof(SHARED_MEM),
|
2004-09-01 04:59:32 +00:00
|
|
|
(void **)&app_client_shm.shm, false
|
2004-08-31 21:02:17 +00:00
|
|
|
);
|
|
|
|
if (shm_handle == NULL) return ERR_SHMGET;
|
|
|
|
}
|
2004-08-11 11:30:25 +00:00
|
|
|
app_client_shm.reset_msgs();
|
|
|
|
|
2004-09-25 19:33:30 +00:00
|
|
|
// NOTE: in Windows, stderr is redirected in boinc_init_diagnostics();
|
2004-08-11 11:30:25 +00:00
|
|
|
|
2004-12-26 03:18:23 +00:00
|
|
|
cmd_line = exec_path + std::string(" ") + wup->command_line;
|
2004-08-11 11:30:25 +00:00
|
|
|
relative_to_absolute(slot_dir, slotdirpath);
|
2005-02-17 21:18:17 +00:00
|
|
|
bool success = false;
|
|
|
|
for (i=0; i<5; i++) {
|
|
|
|
if (CreateProcess(exec_path,
|
|
|
|
(LPSTR)cmd_line.c_str(),
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
FALSE,
|
|
|
|
CREATE_NEW_PROCESS_GROUP|CREATE_NO_WINDOW|IDLE_PRIORITY_CLASS,
|
|
|
|
NULL,
|
|
|
|
slotdirpath,
|
|
|
|
&startup_info,
|
|
|
|
&process_info
|
|
|
|
)) {
|
|
|
|
success = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
windows_error_string(error_msg, sizeof(error_msg));
|
2006-01-17 22:48:09 +00:00
|
|
|
msg_printf(wup->project, MSG_ERROR,
|
|
|
|
"Process creation failed: %s", error_msg
|
|
|
|
);
|
2005-02-17 21:18:17 +00:00
|
|
|
boinc_sleep(drand());
|
|
|
|
}
|
|
|
|
if (!success) {
|
2005-01-21 23:26:36 +00:00
|
|
|
task_state = PROCESS_COULDNT_START;
|
2005-02-17 21:18:17 +00:00
|
|
|
gstate.report_result_error(*result, "CreateProcess() failed - %s", error_msg);
|
2004-08-11 11:30:25 +00:00
|
|
|
return ERR_EXEC;
|
|
|
|
}
|
|
|
|
pid = process_info.dwProcessId;
|
|
|
|
pid_handle = process_info.hProcess;
|
|
|
|
thread_handle = process_info.hThread;
|
2005-12-02 22:29:35 +00:00
|
|
|
|
|
|
|
#elif defined(__EMX__)
|
|
|
|
|
|
|
|
char* argv[100];
|
|
|
|
char current_dir[_MAX_PATH];
|
|
|
|
|
|
|
|
// Set up core/app shared memory seg if needed
|
|
|
|
//
|
|
|
|
if (!app_client_shm.shm) {
|
|
|
|
retval = create_shmem(
|
|
|
|
shmem_seg_name, sizeof(SHARED_MEM), (void**)&app_client_shm.shm
|
|
|
|
);
|
|
|
|
if (retval) {
|
|
|
|
msg_printf(
|
|
|
|
wup->project, MSG_ERROR,
|
|
|
|
"Can't create shared memory: %s", boincerror(retval)
|
|
|
|
);
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
app_client_shm.reset_msgs();
|
|
|
|
|
|
|
|
// save current dir
|
|
|
|
getcwd( current_dir, sizeof(current_dir));
|
|
|
|
|
|
|
|
// chdir() into the slot directory
|
|
|
|
//
|
|
|
|
retval = chdir(slot_dir);
|
|
|
|
if (retval) {
|
|
|
|
msg_printf(wup->project, MSG_ERROR,
|
2006-01-17 22:48:09 +00:00
|
|
|
"Can't change directory: %s", slot_dir, boincerror(retval)
|
2005-12-02 22:29:35 +00:00
|
|
|
);
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
// hook up stderr to a specially-named file
|
|
|
|
//
|
|
|
|
//freopen(STDERR_FILE, "a", stderr);
|
|
|
|
|
|
|
|
argv[0] = exec_name;
|
|
|
|
char cmdline[8192];
|
|
|
|
strcpy(cmdline, wup->command_line.c_str());
|
|
|
|
parse_command_line(cmdline, argv+1);
|
|
|
|
debug_print_argv(argv);
|
2006-03-03 21:34:03 +00:00
|
|
|
sprintf(buf, "../../%s", exec_path );
|
2005-12-02 22:29:35 +00:00
|
|
|
pid = spawnv(P_NOWAIT, buf, argv);
|
|
|
|
if (pid == -1) {
|
|
|
|
msg_printf(wup->project, MSG_ERROR,
|
2006-01-17 22:48:09 +00:00
|
|
|
"Process creation failed: %s\n", buf, boincerror(retval)
|
2005-12-02 22:29:35 +00:00
|
|
|
);
|
|
|
|
chdir(current_dir);
|
|
|
|
return ERR_EXEC;
|
|
|
|
}
|
|
|
|
|
|
|
|
// restore current dir
|
|
|
|
chdir(current_dir);
|
|
|
|
scope_messages.printf("ACTIVE_TASK::start(): forked process: pid %d\n", pid);
|
|
|
|
|
|
|
|
// set idle process priority
|
|
|
|
if (setpriority(PRIO_PROCESS, pid, PROCESS_IDLE_PRIORITY)) {
|
|
|
|
perror("setpriority");
|
|
|
|
}
|
|
|
|
|
2004-08-11 11:30:25 +00:00
|
|
|
#else
|
|
|
|
char* argv[100];
|
|
|
|
|
2004-08-31 21:02:17 +00:00
|
|
|
// Set up core/app shared memory seg if needed
|
2004-08-11 11:30:25 +00:00
|
|
|
//
|
2004-08-31 21:02:17 +00:00
|
|
|
if (!app_client_shm.shm) {
|
|
|
|
retval = create_shmem(
|
|
|
|
shmem_seg_name, sizeof(SHARED_MEM), (void**)&app_client_shm.shm
|
2004-08-11 11:30:25 +00:00
|
|
|
);
|
2004-08-31 21:02:17 +00:00
|
|
|
if (retval) {
|
|
|
|
msg_printf(
|
2005-07-05 09:02:55 +00:00
|
|
|
wup->project, MSG_ERROR,
|
2005-07-24 18:23:56 +00:00
|
|
|
"Can't create shared memory: %s", boincerror(retval)
|
2004-08-31 21:02:17 +00:00
|
|
|
);
|
|
|
|
return retval;
|
|
|
|
}
|
2004-08-11 11:30:25 +00:00
|
|
|
}
|
|
|
|
app_client_shm.reset_msgs();
|
|
|
|
|
2006-02-06 23:44:05 +00:00
|
|
|
#if (defined(__APPLE__) && defined(__i386__))
|
|
|
|
// PowerPC apps emulated on i386 Macs crash if running graphics
|
|
|
|
powerpc_emulated_on_i386 = ! is_native_i386_app(exec_path);
|
|
|
|
#endif
|
|
|
|
|
2004-08-11 11:30:25 +00:00
|
|
|
pid = fork();
|
|
|
|
if (pid == -1) {
|
2005-01-21 23:26:36 +00:00
|
|
|
task_state = PROCESS_COULDNT_START;
|
2004-10-07 19:18:37 +00:00
|
|
|
gstate.report_result_error(*result, "fork() failed: %s", strerror(errno));
|
2006-01-17 22:48:09 +00:00
|
|
|
msg_printf(wup->project, MSG_ERROR,
|
|
|
|
"Process creation failed: %s", strerror(errno)
|
|
|
|
);
|
2004-08-11 11:30:25 +00:00
|
|
|
return ERR_FORK;
|
|
|
|
}
|
|
|
|
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.
|
|
|
|
|
|
|
|
// chdir() into the slot directory
|
|
|
|
//
|
|
|
|
retval = chdir(slot_dir);
|
|
|
|
if (retval) {
|
|
|
|
perror("chdir");
|
2005-10-05 20:39:00 +00:00
|
|
|
fflush(NULL);
|
2004-08-11 11:30:25 +00:00
|
|
|
_exit(retval);
|
|
|
|
}
|
|
|
|
|
|
|
|
// hook up stderr to a specially-named file
|
|
|
|
//
|
|
|
|
freopen(STDERR_FILE, "a", stderr);
|
|
|
|
|
2006-04-14 17:55:02 +00:00
|
|
|
// set idle process priority
|
|
|
|
#ifdef HAVE_SETPRIORITY
|
|
|
|
if (setpriority(PRIO_PROCESS, 0, PROCESS_IDLE_PRIORITY)) {
|
|
|
|
perror("setpriority");
|
|
|
|
}
|
|
|
|
#endif
|
2004-08-11 11:30:25 +00:00
|
|
|
argv[0] = exec_name;
|
2004-12-26 02:55:31 +00:00
|
|
|
char cmdline[8192];
|
|
|
|
strcpy(cmdline, wup->command_line.c_str());
|
|
|
|
parse_command_line(cmdline, argv+1);
|
2004-08-11 11:30:25 +00:00
|
|
|
debug_print_argv(argv);
|
2006-03-03 21:34:03 +00:00
|
|
|
sprintf(buf, "../../%s", exec_path );
|
2004-08-11 11:30:25 +00:00
|
|
|
retval = execv(buf, argv);
|
|
|
|
msg_printf(wup->project, MSG_ERROR,
|
2006-01-17 22:48:09 +00:00
|
|
|
"Process creation (%s) failed: %s\n", buf, boincerror(retval)
|
2004-08-11 11:30:25 +00:00
|
|
|
);
|
|
|
|
perror("execv");
|
2005-10-05 20:39:00 +00:00
|
|
|
fflush(NULL);
|
2004-08-11 11:30:25 +00:00
|
|
|
_exit(errno);
|
|
|
|
}
|
|
|
|
|
|
|
|
scope_messages.printf("ACTIVE_TASK::start(): forked process: pid %d\n", pid);
|
|
|
|
|
|
|
|
#endif
|
2005-01-21 23:26:36 +00:00
|
|
|
task_state = PROCESS_EXECUTING;
|
2004-08-11 11:30:25 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-10-07 19:18:37 +00:00
|
|
|
// Resume the task if it was previously running; otherwise start it
|
|
|
|
// Postcondition: "state" is set correctly
|
2004-08-11 11:30:25 +00:00
|
|
|
//
|
|
|
|
int ACTIVE_TASK::resume_or_start() {
|
2005-02-18 23:50:38 +00:00
|
|
|
const char* str = "??";
|
2004-08-11 11:30:25 +00:00
|
|
|
int retval;
|
|
|
|
|
2005-01-21 23:26:36 +00:00
|
|
|
switch (task_state) {
|
2004-08-23 22:06:48 +00:00
|
|
|
case PROCESS_UNINITIALIZED:
|
2004-08-11 11:30:25 +00:00
|
|
|
if (scheduler_state == CPU_SCHED_UNINITIALIZED) {
|
|
|
|
if (!boinc_file_exists(slot_dir)) {
|
|
|
|
make_slot_dir(slot);
|
|
|
|
}
|
|
|
|
retval = clean_out_dir(slot_dir);
|
2005-10-09 21:03:11 +00:00
|
|
|
if (retval) {
|
|
|
|
retval = rename_slot_dir(slot);
|
|
|
|
if (!retval) retval = make_slot_dir(slot);
|
|
|
|
}
|
2004-08-11 11:30:25 +00:00
|
|
|
retval = start(true);
|
2004-08-24 17:58:51 +00:00
|
|
|
str = "Starting";
|
2004-08-11 11:30:25 +00:00
|
|
|
} else {
|
|
|
|
retval = start(false);
|
2004-08-24 17:58:51 +00:00
|
|
|
str = "Restarting";
|
2004-08-11 11:30:25 +00:00
|
|
|
}
|
2004-10-07 19:18:37 +00:00
|
|
|
if (retval) {
|
2005-01-21 23:26:36 +00:00
|
|
|
task_state = PROCESS_COULDNT_START;
|
2004-10-07 19:18:37 +00:00
|
|
|
return retval;
|
|
|
|
}
|
2004-08-23 22:06:48 +00:00
|
|
|
break;
|
|
|
|
case PROCESS_SUSPENDED:
|
2004-08-11 11:30:25 +00:00
|
|
|
retval = unsuspend();
|
|
|
|
if (retval) {
|
2006-01-17 22:48:09 +00:00
|
|
|
msg_printf(wup->project, MSG_ERROR,
|
|
|
|
"Couldn't resume task %s", result->name
|
2004-08-11 11:30:25 +00:00
|
|
|
);
|
2005-01-21 23:26:36 +00:00
|
|
|
task_state = PROCESS_COULDNT_START;
|
2004-08-11 11:30:25 +00:00
|
|
|
return retval;
|
|
|
|
}
|
2004-08-24 17:58:51 +00:00
|
|
|
str = "Resuming";
|
2004-08-23 22:06:48 +00:00
|
|
|
break;
|
2004-08-24 17:27:08 +00:00
|
|
|
case PROCESS_EXECUTING:
|
|
|
|
return 0;
|
|
|
|
break;
|
2004-08-23 22:06:48 +00:00
|
|
|
default:
|
|
|
|
msg_printf(result->project, MSG_ERROR,
|
2006-01-17 22:48:09 +00:00
|
|
|
"Unexpected state %d for task %s", task_state, result->name
|
2004-08-23 22:06:48 +00:00
|
|
|
);
|
|
|
|
return 0;
|
2004-08-11 11:30:25 +00:00
|
|
|
}
|
2006-05-21 22:03:36 +00:00
|
|
|
if (log_flags.task) {
|
|
|
|
msg_printf(result->project, MSG_INFO,
|
|
|
|
"%s task %s using %s version %d",
|
|
|
|
str,
|
|
|
|
result->name,
|
|
|
|
app_version->app->name,
|
|
|
|
app_version->version_num
|
|
|
|
);
|
|
|
|
}
|
2004-08-11 11:30:25 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Restart active tasks without wiping and reinitializing slot directories
|
|
|
|
// Called at init, with max_tasks = ncpus
|
|
|
|
//
|
|
|
|
int ACTIVE_TASK_SET::restart_tasks(int max_tasks) {
|
|
|
|
vector<ACTIVE_TASK*>::iterator iter;
|
|
|
|
ACTIVE_TASK* atp;
|
|
|
|
RESULT* result;
|
|
|
|
int retval, num_tasks_started;
|
|
|
|
|
|
|
|
SCOPE_MSG_LOG scope_messages(log_messages, CLIENT_MSG_LOG::DEBUG_TASK);
|
|
|
|
|
|
|
|
num_tasks_started = 0;
|
|
|
|
iter = active_tasks.begin();
|
|
|
|
while (iter != active_tasks.end()) {
|
|
|
|
atp = *iter;
|
|
|
|
result = atp->result;
|
|
|
|
atp->init(atp->result);
|
|
|
|
get_slot_dir(atp->slot, atp->slot_dir);
|
|
|
|
if (!gstate.input_files_available(result)) {
|
2006-01-17 22:48:09 +00:00
|
|
|
msg_printf(atp->wup->project, MSG_ERROR,
|
|
|
|
"Can't restart %s: missing files", atp->result->name
|
|
|
|
);
|
2004-08-11 11:30:25 +00:00
|
|
|
gstate.report_result_error(
|
2004-10-07 19:18:37 +00:00
|
|
|
*(atp->result),
|
2004-08-11 11:30:25 +00:00
|
|
|
"One or more missing files"
|
|
|
|
);
|
|
|
|
iter = active_tasks.erase(iter);
|
|
|
|
delete atp;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2004-08-23 22:06:48 +00:00
|
|
|
if (atp->scheduler_state != CPU_SCHED_SCHEDULED
|
2004-08-11 11:30:25 +00:00
|
|
|
|| num_tasks_started >= max_tasks
|
|
|
|
) {
|
|
|
|
msg_printf(atp->wup->project, MSG_INFO,
|
2006-01-17 22:48:09 +00:00
|
|
|
"Deferring task %s",
|
2004-08-11 11:30:25 +00:00
|
|
|
atp->result->name
|
|
|
|
);
|
|
|
|
|
|
|
|
atp->scheduler_state = CPU_SCHED_PREEMPTED;
|
|
|
|
iter++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
msg_printf(atp->wup->project, MSG_INFO,
|
2006-01-17 22:48:09 +00:00
|
|
|
"Resuming task %s using %s version %d",
|
2004-08-11 11:30:25 +00:00
|
|
|
atp->result->name,
|
|
|
|
atp->app_version->app->name,
|
2005-09-02 20:37:26 +00:00
|
|
|
atp->app_version->version_num
|
2004-08-11 11:30:25 +00:00
|
|
|
);
|
|
|
|
retval = atp->start(false);
|
|
|
|
|
|
|
|
if (retval) {
|
2005-07-05 09:02:55 +00:00
|
|
|
msg_printf(atp->wup->project, MSG_ERROR,
|
2006-01-17 22:48:09 +00:00
|
|
|
"Restart of task %s failed: %s\n",
|
|
|
|
atp->result->name, boincerror(retval)
|
2005-07-05 09:02:55 +00:00
|
|
|
);
|
2004-08-11 11:30:25 +00:00
|
|
|
gstate.report_result_error(
|
2004-10-07 19:18:37 +00:00
|
|
|
*(atp->result),
|
2005-07-05 09:02:55 +00:00
|
|
|
"Couldn't restart app: %d", retval
|
2004-08-11 11:30:25 +00:00
|
|
|
);
|
|
|
|
iter = active_tasks.erase(iter);
|
|
|
|
delete atp;
|
|
|
|
} else {
|
|
|
|
++num_tasks_started;
|
|
|
|
iter++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-02-06 23:44:05 +00:00
|
|
|
#if (defined(__APPLE__) && defined(__i386__))
|
|
|
|
|
|
|
|
union headeru {
|
|
|
|
fat_header fat;
|
|
|
|
mach_header mach;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Read the mach-o headers to determine the architectures supported by executable file.
|
|
|
|
// Returns 1 if application can run natively on i386 Macs, else returns 0.
|
|
|
|
int ACTIVE_TASK::is_native_i386_app(char* exec_path) {
|
|
|
|
FILE *f;
|
|
|
|
int result = 0;
|
|
|
|
|
|
|
|
headeru myHeader;
|
|
|
|
fat_arch fatHeader;
|
|
|
|
|
|
|
|
uint32_t n, i, len;
|
|
|
|
|
|
|
|
f = boinc_fopen(exec_path, "rb");
|
|
|
|
if (!f)
|
|
|
|
return result; // Should never happen
|
|
|
|
|
|
|
|
myHeader.fat.magic = 0;
|
|
|
|
myHeader.fat.nfat_arch = 0;
|
|
|
|
|
|
|
|
fread(&myHeader, 1, sizeof(fat_header), f);
|
|
|
|
switch (myHeader.mach.magic) {
|
|
|
|
case MH_MAGIC:
|
|
|
|
if (myHeader.mach.cputype == CPU_TYPE_I386)
|
|
|
|
result = 1; // Single-architecture i386 file
|
|
|
|
break;
|
|
|
|
case FAT_CIGAM:
|
|
|
|
n = _OSSwapInt32(myHeader.fat.nfat_arch); // Multiple architecture (fat) file
|
|
|
|
for (i=0; i<n; i++) {
|
|
|
|
len = fread(&fatHeader, 1, sizeof(fat_arch), f);
|
|
|
|
if (len < sizeof(fat_arch))
|
|
|
|
break; // Should never happen
|
|
|
|
if (fatHeader.cputype == OSSwapConstInt32(CPU_TYPE_I386)) {
|
|
|
|
result = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
fclose (f);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
#endif
|
2004-12-08 00:40:19 +00:00
|
|
|
|
2005-01-02 18:29:53 +00:00
|
|
|
const char *BOINC_RCSID_be8bae8cbb = "$Id$";
|