Select Git revision
test_property.py
Forked from
finesse / pykat
Source project has a limited visibility.
-
Daniel Brown authored
Large amount of changes to the param object which now include being able to put and set parameters and commands. Also adding the modulator component.
Daniel Brown authoredLarge amount of changes to the param object which now include being able to put and set parameters and commands. Also adding the modulator component.
app_start.cpp 30.89 KiB
// This file is part of BOINC.
// http://boinc.berkeley.edu
// Copyright (C) 2008 University of California
//
// BOINC 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 3 of the License, or (at your option) any later version.
//
// BOINC 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.
//
// You should have received a copy of the GNU Lesser General Public License
// along with BOINC. If not, see <http://www.gnu.org/licenses/>.
// initialization and starting of applications
#include "cpp.h"
#ifdef _WIN32
#include "boinc_win.h"
#include "win_util.h"
#ifdef _MSC_VER
#define snprintf _snprintf
#define strdup _strdup
#endif
#else
#include "config.h"
#ifdef HAVE_SCHED_SETSCHEDULER
#include <sched.h>
#endif
#if HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#if HAVE_SYS_RESOURCE_H
#include <sys/resource.h>
#endif
#if HAVE_SYS_IPC_H
#include <sys/ipc.h>
#endif
#if HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif
#include <unistd.h>
#include <cerrno>
#include <sys/stat.h>
#include <string>
#endif
#ifdef __EMX__
#include <process.h>
#endif
#if (defined (__APPLE__) && (defined(__i386__) || defined(__x86_64__)))
#include <mach-o/loader.h>
#include <mach-o/fat.h>
#include <mach/machine.h>
#include <libkern/OSByteOrder.h>
#endif
#if(!defined (_WIN32) && !defined (__EMX__))
#include <fcntl.h>
#endif
#include <vector>
using std::vector;
using std::string;
#include "filesys.h"
#include "error_numbers.h"
#include "util.h"
#include "str_util.h"
#include "str_replace.h"
#include "shmem.h"
#include "client_msgs.h"
#include "client_state.h"
#include "file_names.h"
#include "base64.h"
#include "sandbox.h"
#include "unix_util.h"
#ifdef _WIN32
#include "proc_control.h"
#endif
#include "app.h"
#ifdef _WIN32
// Dynamically link to these functions at runtime;
// otherwise BOINC cannot run on Win98
// CreateEnvironmentBlock
typedef BOOL (WINAPI *tCEB)(LPVOID *lpEnvironment, HANDLE hToken, BOOL bInherit);
// DestroyEnvironmentBlock
typedef BOOL (WINAPI *tDEB)(LPVOID lpEnvironment);
#endif
// Goes through an array of strings, and prints each string
//
#ifndef _WIN32
static void debug_print_argv(char** argv) {
msg_printf(0, MSG_INFO, "[task_debug] Arguments:");
for (int i=0; argv[i]; i++) {
msg_printf(0, MSG_INFO,
"[task_debug] argv[%d]: %s\n", i, argv[i]
);
}
}
#endif
// For apps that use coprocessors, append "--device x" to the command line.
//
static void coproc_cmdline(
int rsc_type, RESULT* rp, double ninstances, char* cmdline
) {
COPROC* coproc = (rsc_type==RSC_TYPE_CUDA)?(COPROC*)coproc_cuda:(COPROC*)coproc_ati;
for (int j=0; j<ninstances; j++) {
int k = rp->coproc_indices[j];
// sanity check
//
if (k < 0 || k >= coproc->count) {
*(int*)1 = 0;
}
char buf[256];
sprintf(buf, " --device %d", coproc->device_nums[k]);
strcat(cmdline, buf);
}
}
// Make a unique key for core/app shared memory segment.
// Windows: also create and attach to the segment.
//
int ACTIVE_TASK::get_shmem_seg_name() {
#ifdef _WIN32
int i;
char seg_name[256];
bool try_global = (sandbox_account_service_token != NULL);
for (i=0; i<1024; i++) {
sprintf(seg_name, "%sboinc_%d", SHM_PREFIX, i);
shm_handle = create_shmem(
seg_name, sizeof(SHARED_MEM), (void**)&app_client_shm.shm,
try_global
);
if (shm_handle) break;
}
if (!shm_handle) return ERR_SHMGET;
sprintf(shmem_seg_name, "boinc_%d", i);
#else
char init_data_path[256];
#ifndef __EMX__
// shmem_seg_name is not used with mmap() shared memory
if (app_version->api_major_version() >= 6) {
shmem_seg_name = -1;
return 0;
}
#endif
sprintf(init_data_path, "%s/%s", slot_dir, INIT_DATA_FILE);
// ftok() only works if there's a file at the given location
//
FILE* f = boinc_fopen(init_data_path, "w");
if (f) fclose(f);
shmem_seg_name = ftok(init_data_path, 1);
if (shmem_seg_name == -1) return ERR_SHMEM_NAME;
#endif
return 0;
}
// write the app init file.
// This is done before starting the app,
// and when project prefs have changed during app execution
//
int ACTIVE_TASK::write_app_init_file() {
APP_INIT_DATA aid;
FILE *f;
char init_data_path[256], project_dir[256], project_path[256];
int retval;
aid.major_version = BOINC_MAJOR_VERSION;
aid.minor_version = BOINC_MINOR_VERSION;
aid.release = BOINC_RELEASE;
aid.app_version = app_version->version_num;
safe_strcpy(aid.app_name, wup->app->name);
safe_strcpy(aid.symstore, wup->project->symstore);
safe_strcpy(aid.acct_mgr_url, gstate.acct_mgr_info.acct_mgr_url);
if (wup->project->project_specific_prefs.length()) {
aid.project_preferences = strdup(wup->project->project_specific_prefs.c_str());
}
aid.hostid = wup->project->hostid;
safe_strcpy(aid.user_name, wup->project->user_name);
safe_strcpy(aid.team_name, wup->project->team_name);
get_project_dir(wup->project, project_dir, sizeof(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;
double rrs = gstate.runnable_resource_share();
if (rrs) {
aid.resource_share_fraction = wup->project->resource_share/rrs;
} else {
aid.resource_share_fraction = 1;
}
aid.rsc_fpops_est = wup->rsc_fpops_est;
aid.rsc_fpops_bound = wup->rsc_fpops_bound;
aid.rsc_memory_bound = wup->rsc_memory_bound;
aid.rsc_disk_bound = wup->rsc_disk_bound;
aid.computation_deadline = result->computation_deadline();
aid.checkpoint_period = gstate.global_prefs.disk_interval;
aid.fraction_done_start = 0;
aid.fraction_done_end = 1;
#ifdef _WIN32
strcpy(aid.shmem_seg_name, shmem_seg_name);
#else
aid.shmem_seg_name = shmem_seg_name;
#endif
aid.wu_cpu_time = checkpoint_cpu_time;
aid.starting_elapsed_time = checkpoint_elapsed_time;
sprintf(init_data_path, "%s/%s", slot_dir, INIT_DATA_FILE);
f = boinc_fopen(init_data_path, "w");
if (!f) {
msg_printf(wup->project, MSG_INTERNAL_ERROR,
"Failed to open init file %s",
init_data_path
);
return ERR_FOPEN;
}
aid.host_info = gstate.host_info;
aid.global_prefs = gstate.global_prefs;
aid.proxy_info = gstate.proxy_info;
retval = write_init_data_file(f, aid);
fclose(f);
return retval;
}
// set up a file reference, given a slot dir and project dir.
// This means:
// 1) copy the file to slot dir, if reference is by copy
// 2) else make a soft link
//
static int setup_file(
PROJECT* project, FILE_INFO* fip, FILE_REF& fref,
char* file_path, char* slot_dir, bool input
) {
char link_path[256], rel_file_path[256];
int retval;
sprintf(link_path,
"%s/%s",
slot_dir, strlen(fref.open_name)?fref.open_name:fip->name
);
sprintf(rel_file_path, "../../%s", file_path );
// if anonymous platform, this is called even if not first time,
// so link may already be there
//
if (input && project->anonymous_platform && boinc_file_exists(link_path)) {
return 0;
}
if (fref.copy_file) {
if (input) {
retval = boinc_copy(file_path, link_path);
if (retval) {
msg_printf(project, MSG_INTERNAL_ERROR,
"Can't copy %s to %s: %s", file_path, link_path,
boincerror(retval)
);
return retval;
}
#ifdef SANDBOX
return set_to_project_group(link_path);
#endif
}
return 0;
}
#ifdef _WIN32
retval = make_soft_link(project, link_path, rel_file_path);
if (retval) return retval;
#else
if (project->use_symlinks) {
retval = symlink(rel_file_path, link_path);
} else {
retval = make_soft_link(project, link_path, rel_file_path);
}
if (retval) return retval;
#endif
#ifdef SANDBOX
return set_to_project_group(link_path);
#endif
return 0;
}
int ACTIVE_TASK::link_user_files() {
PROJECT* project = wup->project;
unsigned int i;
FILE_REF fref;
FILE_INFO* fip;
char file_path[1024];
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, sizeof(file_path));
setup_file(project, fip, fref, file_path, slot_dir, true);
}
return 0;
}
int ACTIVE_TASK::copy_output_files() {
char slotfile[256], projfile[256];
unsigned int i;
for (i=0; i<result->output_files.size(); i++) {
FILE_REF& fref = result->output_files[i];
if (!fref.copy_file) continue;
FILE_INFO* fip = fref.file_info;
sprintf(slotfile, "%s/%s", slot_dir, fref.open_name);
get_pathname(fip, projfile, sizeof(projfile));
#if 1
boinc_rename(slotfile, projfile);
#else
int retval = boinc_rename(slotfile, projfile);
// this isn't a BOINC error.
// it just means the app didn't create an output file
// that it was supposed to.
//
if (retval) {
msg_printf(wup->project, MSG_INTERNAL_ERROR,
"Can't rename output file %s to %s: %s",
fip->name, projfile, boincerror(retval)
);
}
#endif
}
return 0;
}
// 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
//
// postcondition:
// If any error occurs
// ACTIVE_TASK::task_state is PROCESS_COULDNT_START
// report_result_error() is called
// else
// ACTIVE_TASK::task_state is PROCESS_EXECUTING
//
int ACTIVE_TASK::start(bool first_time) {
char exec_name[256], file_path[256], buf[256], exec_path[256];
char cmdline[8192];
unsigned int i;
FILE_REF fref;
FILE_INFO* fip;
int retval;
// if this job less than one CPU, run it at above idle priority
//
bool high_priority = (app_version->avg_ncpus < 1);
if (first_time && log_flags.task) {
msg_printf(wup->project, MSG_INFO,
"Starting %s", result->name
);
}
if (log_flags.cpu_sched) {
msg_printf(wup->project, MSG_INFO,
"[cpu_sched] Starting %s%s", result->name, first_time?" (initial)":"(resume)"
);
}
if (wup->project->verify_files_on_app_start) {
fip=0;
retval = gstate.input_files_available(result, true, &fip);
if (retval) {
if (fip) {
snprintf(
buf, sizeof(buf), "Input file %s missing or invalid: %d", fip->name, retval
);
} else {
strcpy(buf, "Input file missing or invalid");
}
goto error;
}
}
current_cpu_time = checkpoint_cpu_time;
graphics_request_queue.init(result->name); // reset message queues
process_control_queue.init(result->name);
if (!app_client_shm.shm) {
retval = get_shmem_seg_name();
if (retval) {
sprintf(buf,
"Can't get shared memory segment name: %s",
boincerror(retval)
);
goto error;
}
}
// this must go AFTER creating shmem name,
// since the shmem name is part of the file
//
retval = write_app_init_file();
if (retval) {
sprintf(buf, "Can't write init file: %d", retval);
goto error;
}
// set up applications files
//
strcpy(exec_name, "");
for (i=0; i<app_version->app_files.size(); i++) {
fref = app_version->app_files[i];
fip = fref.file_info;
get_pathname(fip, file_path, sizeof(file_path));
if (fref.main_program) {
if (is_image_file(fip->name)) {
sprintf(buf, "Main program %s is an image file", fip->name);
retval = ERR_NO_SIGNATURE;
goto error;
}
if (!fip->executable && !wup->project->anonymous_platform) {
sprintf(buf, "Main program %s is not executable", fip->name);
retval = ERR_NO_SIGNATURE;
goto error;
}
safe_strcpy(exec_name, fip->name);
safe_strcpy(exec_path, file_path);
}
// anonymous platform may use different files than
// when the result was started, so link files even if not first time
//
if (first_time || wup->project->anonymous_platform) {
retval = setup_file(result->project, fip, fref, file_path, slot_dir, true);
if (retval) {
strcpy(buf, "Can't link input file");
goto error;
}
}
}
if (!strlen(exec_name)) {
strcpy(buf, "No main program specified");
retval = ERR_NOT_FOUND;
goto error;
}
// set up input, output files
//
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, sizeof(file_path));
retval = setup_file(result->project, fip, fref, file_path, slot_dir, true);
if (retval) {
strcpy(buf, "Can't link input file");
goto error;
}
}
for (i=0; i<result->output_files.size(); i++) {
fref = result->output_files[i];
if (fref.copy_file) continue;
fip = fref.file_info;
get_pathname(fref.file_info, file_path, sizeof(file_path));
retval = setup_file(result->project, fip, fref, file_path, slot_dir, false);
if (retval) {
strcpy(buf, "Can't link output file");
goto error;
}
}
}
link_user_files();
if (gstate.exit_before_start) {
exit(0);
}
#ifdef _WIN32
PROCESS_INFORMATION process_info;
STARTUPINFO startup_info;
LPVOID environment_block = NULL;
char slotdirpath[256];
char error_msg[1024];
char error_msg2[1024];
memset(&process_info, 0, sizeof(process_info));
memset(&startup_info, 0, sizeof(startup_info));
startup_info.cb = sizeof(startup_info);
// suppress 2-sec rotating hourglass cursor on startup
//
startup_info.dwFlags = STARTF_FORCEOFFFEEDBACK;
app_client_shm.reset_msgs();
if (config.run_apps_manually) {
// fill in core client's PID so we won't think app has exited
//
pid = GetCurrentProcessId();
pid_handle = GetCurrentProcess();
set_task_state(PROCESS_EXECUTING, "start");
return 0;
}
sprintf(cmdline, "%s %s %s",
exec_path, wup->command_line.c_str(), app_version->cmdline
);
if (app_version->ncudas) {
coproc_cmdline(RSC_TYPE_CUDA, result, app_version->ncudas, cmdline);
}
if (app_version->natis) {
coproc_cmdline(RSC_TYPE_ATI, result, app_version->natis, cmdline);
}
relative_to_absolute(slot_dir, slotdirpath);
bool success = false;
int prio_mask;
if (config.no_priority_change) {
prio_mask = 0;
} else if (high_priority) {
prio_mask = BELOW_NORMAL_PRIORITY_CLASS;
} else {
prio_mask = IDLE_PRIORITY_CLASS;
}
for (i=0; i<5; i++) {
if (sandbox_account_service_token != NULL) {
// Find CreateEnvironmentBlock/DestroyEnvironmentBlock pointers
tCEB pCEB = NULL;
tDEB pDEB = NULL;
HMODULE hUserEnvLib = NULL;
hUserEnvLib = LoadLibrary("userenv.dll");
if (hUserEnvLib) {
pCEB = (tCEB) GetProcAddress(hUserEnvLib, "CreateEnvironmentBlock");
pDEB = (tDEB) GetProcAddress(hUserEnvLib, "DestroyEnvironmentBlock");
}
if (!pCEB(&environment_block, sandbox_account_service_token, FALSE)) {
if (log_flags.task) {
windows_error_string(error_msg, sizeof(error_msg));
msg_printf(wup->project, MSG_INFO,
"Process environment block creation failed: %s", error_msg
);
}
}
if (CreateProcessAsUser(
sandbox_account_service_token,
exec_path,
cmdline,
NULL,
NULL,
FALSE,
CREATE_NEW_PROCESS_GROUP|CREATE_NO_WINDOW|prio_mask|CREATE_UNICODE_ENVIRONMENT,
environment_block,
slotdirpath,
&startup_info,
&process_info
)) {
success = true;
break;
} else {
windows_error_string(error_msg, sizeof(error_msg));
msg_printf(wup->project, MSG_INTERNAL_ERROR,
"Process creation failed: %s", error_msg
);
}
if (!pDEB(environment_block)) {
if (log_flags.task) {
windows_error_string(error_msg, sizeof(error_msg2));
msg_printf(wup->project, MSG_INFO,
"Process environment block cleanup failed: %s",
error_msg2
);
}
}
if (hUserEnvLib) {
pCEB = NULL;
pDEB = NULL;
FreeLibrary(hUserEnvLib);
}
} else {
if (CreateProcess(
exec_path,
cmdline,
NULL,
NULL,
FALSE,
CREATE_NEW_PROCESS_GROUP|CREATE_NO_WINDOW|prio_mask,
NULL,
slotdirpath,
&startup_info,
&process_info
)) {
success = true;
break;
} else {
windows_error_string(error_msg, sizeof(error_msg));
msg_printf(wup->project, MSG_INTERNAL_ERROR,
"Process creation failed: %s", error_msg
);
}
}
boinc_sleep(drand());
}
if (!success) {
sprintf(buf, "CreateProcess() failed - %s", error_msg);
retval = ERR_EXEC;
goto error;
}
pid = process_info.dwProcessId;
pid_handle = process_info.hProcess;
CloseHandle(process_info.hThread); // thread handle is not used
#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) {
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) {
sprintf(buf, "Can't change directory: %s", slot_dir, boincerror(retval));
goto error;
}
// 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());
if (strlen(result->cmdline)) {
strcat(cmdline, " ");
strcat(cmdline, result->cmdline);
}
parse_command_line(cmdline, argv+1);
if (log_flags.task_debug) {
debug_print_argv(argv);
}
sprintf(buf, "../../%s", exec_path );
pid = spawnv(P_NOWAIT, buf, argv);
if (pid == -1) {
sprintf(buf, "Process creation failed: %s\n", buf, boincerror(retval));
chdir(current_dir);
retval = ERR_EXEC;
goto error;
}
// restore current dir
chdir(current_dir);
if (log_flags.task_debug) {
msg_printf(wup->project, MSG_INFO,
"[task_debug] ACTIVE_TASK::start(): forked process: pid %d\n", pid
);
}
if (!config.no_priority_change) {
if (setpriority(PRIO_PROCESS, pid,
high_priority?PROCESS_MEDIUM_PRIORITY:PROCESS_IDLE_PRIORITY)
) {
perror("setpriority");
}
}
#else
// Unix/Linux/Mac case
char* argv[100];
char current_dir[1024];
getcwd(current_dir, sizeof(current_dir));
sprintf(cmdline, "%s %s",
wup->command_line.c_str(), app_version->cmdline
);
if (app_version->ncudas) {
coproc_cmdline(RSC_TYPE_CUDA, result, app_version->ncudas, cmdline);
}
if (app_version->natis) {
coproc_cmdline(RSC_TYPE_ATI, result, app_version->natis, cmdline);
}
// Set up core/app shared memory seg if needed
//
if (!app_client_shm.shm) {
if (app_version->api_major_version() >= 6) {
// Use mmap() shared memory
sprintf(buf, "%s/%s", slot_dir, MMAPPED_FILE_NAME);
if (g_use_sandbox) {
if (!boinc_file_exists(buf)) {
int fd = open(buf, O_RDWR | O_CREAT, 0660);
if (fd >= 0) {
close (fd);
#ifdef SANDBOX
set_to_project_group(buf);
#endif
}
}
}
retval = create_shmem_mmap(
buf, sizeof(SHARED_MEM), (void**)&app_client_shm.shm
);
} else {
// Use shmget() shared memory
retval = create_shmem(
shmem_seg_name, sizeof(SHARED_MEM), gstate.boinc_project_gid,
(void**)&app_client_shm.shm
);
if (retval) {
needs_shmem = true;
destroy_shmem(shmem_seg_name);
return retval;
}
}
needs_shmem = false;
}
app_client_shm.reset_msgs();
#if (defined (__APPLE__) && (defined(__i386__) || defined(__x86_64__)))
// PowerPC apps emulated on i386 Macs crash if running graphics
powerpc_emulated_on_i386 = ! is_native_i386_app(exec_path);
#endif
if (config.run_apps_manually) {
pid = getpid(); // use the client's PID
set_task_state(PROCESS_EXECUTING, "start");
return 0;
}
pid = fork();
if (pid == -1) {
sprintf(buf, "fork() failed: %s", strerror(errno));
retval = ERR_FORK;
goto error;
}
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.
// don't pass stdout to the app
//
int fd = open("/dev/null", O_RDWR);
dup2(fd, STDOUT_FILENO);
close(fd);
// prepend to library path:
// - the project dir (../../projects/X)
// - the slot dir (.)
// - the BOINC dir (../..)
// We use relative paths in case higher-level dirs
// are not readable to the account under which app runs
//
char libpath[8192];
get_project_dir(wup->project, buf, sizeof(buf));
char* p = getenv("LD_LIBRARY_PATH");
if (p) {
sprintf(libpath, "../../%s:.:../..:%s", buf, p);
} else {
sprintf(libpath, "../../%s:.:../..", buf);
}
setenv("LD_LIBRARY_PATH", libpath, 1);
// On the Mac, do the same for DYLIB_LIBRARY_PATH
//
#ifdef __APPLE__
p = getenv("DYLIB_LIBRARY_PATH");
if (p) {
sprintf(libpath, "../../%s:.:../..:%s", buf, p);
} else {
sprintf(libpath, "../../%s:.:../..", buf);
}
setenv("DYLIB_LIBRARY_PATH", libpath, 1);
#endif
retval = chdir(slot_dir);
if (retval) {
perror("chdir");
fflush(NULL);
_exit(errno);
}
#if 0
// set stack size limit to the max.
// Some BOINC apps have reported problems with exceeding
// small stack limits (e.g. 8 MB)
// and it seems like the best thing to raise it as high as possible
//
struct rlimit rlim;
#define MIN_STACK_LIMIT 64000000
getrlimit(RLIMIT_STACK, &rlim);
if (rlim.rlim_cur != RLIM_INFINITY && rlim.rlim_cur <= MIN_STACK_LIMIT) {
if (rlim.rlim_max == RLIM_INFINITY || rlim.rlim_max > MIN_STACK_LIMIT) {
rlim.rlim_cur = MIN_STACK_LIMIT;
} else {
rlim.rlim_cur = rlim.rlim_max;
}
setrlimit(RLIMIT_STACK, &rlim);
}
#endif
// hook up stderr to a specially-named file
//
freopen(STDERR_FILE, "a", stderr);
if (!config.no_priority_change) {
#ifdef HAVE_SETPRIORITY
if (setpriority(PRIO_PROCESS, 0,
high_priority?PROCESS_MEDIUM_PRIORITY:PROCESS_IDLE_PRIORITY)
) {
perror("setpriority");
}
#endif
#ifdef HAVE_SCHED_SETSCHEDULER
if (!high_priority) {
struct sched_param p;
p.sched_priority = 0;
if (sched_setscheduler(0, SCHED_BATCH, &p)) {
perror("sched_setscheduler");
}
}
#endif
}
sprintf(buf, "../../%s", exec_path );
if (g_use_sandbox) {
char switcher_path[100];
sprintf(switcher_path, "../../%s/%s",
SWITCHER_DIR, SWITCHER_FILE_NAME
);
argv[0] = SWITCHER_FILE_NAME;
argv[1] = buf;
argv[2] = exec_name;
parse_command_line(cmdline, argv+3);
if (log_flags.task_debug) {
debug_print_argv(argv);
}
// Files written by projects have user boinc_project
// and group boinc_project,
// so they must be world-readable so BOINC CLient can read them
//
umask(2);
retval = execv(switcher_path, argv);
} else {
argv[0] = buf;
parse_command_line(cmdline, argv+1);
retval = execv(buf, argv);
}
msg_printf(wup->project, MSG_INTERNAL_ERROR,
"Process creation (%s) failed: %s, errno=%d\n",
buf, boincerror(retval), errno
);
perror("execv");
fflush(NULL);
_exit(errno);
}
if (log_flags.task_debug) {
msg_printf(wup->project, MSG_INFO,
"[task_debug] ACTIVE_TASK::start(): forked process: pid %d\n", pid
);
}
#endif
set_task_state(PROCESS_EXECUTING, "start");
return 0;
// go here on error; "buf" contains error message, "retval" is nonzero
//
error:
// if something failed, it's possible that the executable was munged.
// Verify it to trigger another download.
//
gstate.input_files_available(result, true);
gstate.report_result_error(*result, buf);
if (log_flags.task_debug) {
msg_printf(wup->project, MSG_INFO,
"[task_debug] couldn't start app: %s", buf
);
}
set_task_state(PROCESS_COULDNT_START, "start");
return retval;
}
// Resume the task if it was previously running; otherwise start it
// Postcondition: "state" is set correctly
//
int ACTIVE_TASK::resume_or_start(bool first_time) {
const char* str = "??";
int retval;
switch (task_state()) {
case PROCESS_UNINITIALIZED:
if (first_time) {
retval = start(true);
str = "Starting";
} else {
retval = start(false);
str = "Restarting";
}
if ((retval == ERR_SHMGET) || (retval == ERR_SHMAT)) {
return retval;
}
if (retval) {
set_task_state(PROCESS_COULDNT_START, "resume_or_start1");
return retval;
}
break;
case PROCESS_SUSPENDED:
retval = unsuspend();
if (retval) {
msg_printf(wup->project, MSG_INTERNAL_ERROR,
"Couldn't resume task %s", result->name
);
set_task_state(PROCESS_COULDNT_START, "resume_or_start2");
return retval;
}
str = "Resuming";
break;
default:
msg_printf(result->project, MSG_INTERNAL_ERROR,
"Unexpected state %d for task %s", task_state(), result->name
);
return 0;
}
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
);
}
return 0;
}
#if (defined (__APPLE__) && (defined(__i386__) || defined(__x86_64__)))
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 / x86_64 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;
uint32_t theMagic;
integer_t theType;
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);
theMagic = myHeader.mach.magic;
switch (theMagic) {
case MH_CIGAM:
case MH_MAGIC:
case MH_MAGIC_64:
case MH_CIGAM_64:
theType = myHeader.mach.cputype;
if ((theMagic == MH_CIGAM) || (theMagic == MH_CIGAM_64)) {
theType = OSSwapInt32(theType);
}
if ((theType == CPU_TYPE_I386) || (theType == CPU_TYPE_X86_64)) {
result = 1; // Single-architecture i386or x86_64 file
}
break;
case FAT_MAGIC:
case FAT_CIGAM:
n = myHeader.fat.nfat_arch;
if (theMagic == 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
}
theType = fatHeader.cputype;
if (theMagic == FAT_CIGAM) {
theType = OSSwapInt32(theType);
}
if ((theType == CPU_TYPE_I386) || (theType == CPU_TYPE_X86_64)) {
result = 1;
break;
}
}
break;
default:
break;
}
fclose (f);
return result;
}
#endif
const char *BOINC_RCSID_be8bae8cbb = "$Id$";