Merge pull request #4141 from BOINC/dpa_graphics_exec2

Check graphics app before telling GUI about it
This commit is contained in:
David Anderson 2021-01-19 14:07:53 -08:00 committed by GitHub
commit ba3702e8c8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 181 additions and 153 deletions

View File

@ -759,6 +759,10 @@ int ACTIVE_TASK::write_gui(MIOFILE& fout) {
(fd - first_fraction_done)/(elapsed_time - first_fraction_done_elapsed_time)
);
}
// only report a graphics app if file exists and we can execute it
//
app_version->check_graphics_exec();
if (strlen(app_version->graphics_exec_path)) {
fout.printf(
" <graphics_exec_path>%s</graphics_exec_path>\n"
@ -767,6 +771,7 @@ int ACTIVE_TASK::write_gui(MIOFILE& fout) {
slot_path
);
}
if (strlen(web_graphics_url)) {
fout.printf(
" <web_graphics_url>%s</web_graphics_url>\n",

View File

@ -15,17 +15,6 @@
// You should have received a copy of the GNU Lesser General Public License
// along with BOINC. If not, see <http://www.gnu.org/licenses/>.
#ifdef __APPLE__
#include <sys/types.h>
#include <sys/sysctl.h>
#include <mach-o/loader.h>
#include <mach-o/fat.h>
#include <mach/machine.h>
#include <libkern/OSByteOrder.h>
extern int compareOSVersionTo(int toMajor, int toMinor);
#endif
#ifdef _WIN32
#include "boinc_win.h"
#else
@ -1325,17 +1314,7 @@ int CLIENT_STATE::link_app_version(PROJECT* p, APP_VERSION* avp) {
}
if (!strcmp(file_ref.open_name, GRAPHICS_APP_FILENAME)) {
char relpath[MAXPATHLEN], path[MAXPATHLEN];
get_pathname(fip, relpath, sizeof(relpath));
relative_to_absolute(relpath, path);
#ifdef __APPLE__
if (can_run_on_this_CPU(path))
#endif
{
safe_strcpy(avp->graphics_exec_path, path);
safe_strcpy(avp->graphics_exec_file, fip->name);
}
avp->graphics_exec_fip = fip;
}
// any file associated with an app version must be signed
@ -2373,125 +2352,3 @@ bool CLIENT_STATE::abort_sequence_done() {
}
#endif
#ifdef __APPLE__
union headeru {
fat_header fat;
mach_header mach;
};
// Get the architecture of this computer's CPU: x86_64 or arm64.
// Read the executable file's mach-o headers to determine the
// architecture(s) of its code.
// Returns 1 if application can run natively on this computer,
// else returns 0.
//
// ToDo: determine whether x86_64 graphics apps emulated on arm64 Macs
// properly run under Rosetta 2. Note: years ago, PowerPC apps emulated
// by Rosetta on i386 Macs crashed when running graphics.
//
int CLIENT_STATE::can_run_on_this_CPU(char* exec_path) {
FILE *f;
int retval = 0;
headeru myHeader;
fat_arch fatHeader;
static bool x86_64_CPU = false;
static bool arm64_cpu = false;
static bool need_CPU_architecture = true;
uint32_t n, i, len;
uint32_t theMagic;
integer_t file_architecture;
if (need_CPU_architecture) {
// Determine the architecture of the CPU we are running on
// ToDo: adjust this code accordingly.
uint32_t cputype = 0;
size_t size = sizeof (cputype);
int res = sysctlbyname ("hw.cputype", &cputype, &size, NULL, 0);
if (res) return false; // Should never happen
// Since we require MacOS >= 10.7, the CPU must be x86_64 or arm64
x86_64_CPU = ((cputype &0xff) == CPU_TYPE_X86);
arm64_cpu = ((cputype &0xff) == CPU_TYPE_ARM);
need_CPU_architecture = false;
}
f = boinc_fopen(exec_path, "rb");
if (!f) {
return retval; // 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:
file_architecture = myHeader.mach.cputype;
if ((theMagic == MH_CIGAM) || (theMagic == MH_CIGAM_64)) {
file_architecture = OSSwapInt32(file_architecture);
}
if (x86_64_CPU && (file_architecture == CPU_TYPE_I386)) {
// Single-architecture i386 file on x86_64 CPU
if (compareOSVersionTo(10, 15) < 0) { // OS >= 10.15 are 64-bit only
retval = 1;
}
} else
if (x86_64_CPU && (file_architecture == CPU_TYPE_X86_64)) {
retval = 1; // Single-architecture x86_64 file on x86_64 CPU
} else
if (arm64_cpu && (file_architecture == CPU_TYPE_ARM64)) {
retval = 1; // Single-architecture arm64 file on arm64 CPU
} else
if (arm64_cpu && (file_architecture == CPU_TYPE_X86_64)) {
retval = 1; // Single-architecture x86_64 file emulated on arm64 CPU
// ToDo: determine whether emulated graphics apps work properly
}
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
}
file_architecture = fatHeader.cputype;
if (theMagic == FAT_CIGAM) {
file_architecture = OSSwapInt32(file_architecture);
}
if (x86_64_CPU && (file_architecture == CPU_TYPE_X86_64)) {
retval = 1; // file with x86_64 architecture on x86_64 CPU
break;
} else
if (arm64_cpu && (file_architecture == CPU_TYPE_ARM64)) {
retval = 1; // file with arm64 architecture on arm64 CPU
break;
} else
if (arm64_cpu && (file_architecture == CPU_TYPE_X86_64)) {
retval = 1; // file with x86_64 architecture emulated on arm64 CPU
// ToDo: determine whether emulated graphics apps work properly
}
}
break;
default:
break;
}
fclose (f);
return retval;
}
#endif

View File

@ -296,10 +296,6 @@ struct CLIENT_STATE {
void clear_absolute_times();
void set_now();
void log_show_projects();
#ifdef __APPLE__
// Check whether the app can run on this CPU architecture
int can_run_on_this_CPU(char* exec_path);
#endif
// --------------- cpu_sched.cpp:
double total_resource_share();

View File

@ -780,6 +780,7 @@ void APP_VERSION::init() {
app = NULL;
project = NULL;
ref_cnt = 0;
graphics_exec_fip = NULL;
safe_strcpy(graphics_exec_path,"");
safe_strcpy(graphics_exec_file, "");
max_working_set_size = 0;
@ -1039,6 +1040,37 @@ bool APP_VERSION::api_version_at_least(int major, int minor) {
return min >= minor;
}
// If app version has a graphics program,
// see whether the exec is present and can be run.
// If so fill in the file name and path.
// Called from GUI RPC handler.
//
void APP_VERSION::check_graphics_exec() {
if (!graphics_exec_fip) return;
if (strlen(graphics_exec_path)) return;
if (graphics_exec_fip->status < 0) {
// download or verify of graphics exec failed; don't check again
//
graphics_exec_fip = NULL;
return;
}
if (graphics_exec_fip->status != FILE_PRESENT) return;
char relpath[MAXPATHLEN], path[MAXPATHLEN];
get_pathname(graphics_exec_fip, relpath, sizeof(relpath));
relative_to_absolute(relpath, path);
#ifdef __APPLE__
if (!can_run_on_this_CPU(path)) {
// if can't run this exec, don't check again
//
graphics_exec_fip = NULL;
return;
}
#endif
safe_strcpy(graphics_exec_path, path);
safe_strcpy(graphics_exec_file, graphics_exec_fip->name);
}
int FILE_REF::parse(XML_PARSER& xp) {
bool temp;

View File

@ -296,6 +296,8 @@ struct GPU_USAGE {
double usage;
};
// if you add anything, initialize it in init()
//
struct APP_VERSION {
char app_name[256];
int version_num;
@ -317,8 +319,14 @@ struct APP_VERSION {
PROJECT* project;
std::vector<FILE_REF> app_files;
int ref_cnt;
// graphics app, if any
// the strings are filled in after exec is downloaded and verified
//
FILE_INFO *graphics_exec_fip;
char graphics_exec_path[MAXPATHLEN];
char graphics_exec_file[256];
double max_working_set_size;
// max working set of tasks using this app version.
// unstarted jobs using this app version are assumed
@ -361,6 +369,7 @@ struct APP_VERSION {
inline bool is_opencl() {
return (strstr(plan_class, "opencl") != NULL);
}
void check_graphics_exec();
};
struct WORKUNIT {

View File

@ -124,6 +124,14 @@ using std::min;
#include <IOKit/IOKitLib.h>
#include <Carbon/Carbon.h>
#include <CoreFoundation/CoreFoundation.h>
#include <sys/types.h>
#include <sys/sysctl.h>
#include <mach-o/loader.h>
#include <mach-o/fat.h>
#include <mach/machine.h>
#include <libkern/OSByteOrder.h>
extern int compareOSVersionTo(int toMajor, int toMinor);
#ifdef __cplusplus
extern "C" {
@ -1988,3 +1996,122 @@ long HOST_INFO::user_idle_time(bool check_all_logins) {
}
#endif // ! __APPLE__
#ifdef __APPLE__
union headeru {
fat_header fat;
mach_header mach;
};
// Get the architecture of this computer's CPU: x86_64 or arm64.
// Read the executable file's mach-o headers to determine the
// architecture(s) of its code.
// Returns 1 if application can run natively on this computer,
// else returns 0.
//
// ToDo: determine whether x86_64 graphics apps emulated on arm64 Macs
// properly run under Rosetta 2. Note: years ago, PowerPC apps emulated
// by Rosetta on i386 Macs crashed when running graphics.
//
bool can_run_on_this_CPU(char* exec_path) {
FILE *f;
int retval = false;
headeru myHeader;
fat_arch fatHeader;
static bool x86_64_CPU = false;
static bool arm64_cpu = false;
static bool need_CPU_architecture = true;
uint32_t n, i, len;
uint32_t theMagic;
integer_t file_architecture;
if (need_CPU_architecture) {
// Determine the architecture of the CPU we are running on
// ToDo: adjust this code accordingly.
uint32_t cputype = 0;
size_t size = sizeof (cputype);
int res = sysctlbyname ("hw.cputype", &cputype, &size, NULL, 0);
if (res) return false; // Should never happen
// Since we require MacOS >= 10.7, the CPU must be x86_64 or arm64
x86_64_CPU = ((cputype &0xff) == CPU_TYPE_X86);
arm64_cpu = ((cputype &0xff) == CPU_TYPE_ARM);
need_CPU_architecture = false;
}
f = boinc_fopen(exec_path, "rb");
if (!f) {
return retval; // 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:
file_architecture = myHeader.mach.cputype;
if ((theMagic == MH_CIGAM) || (theMagic == MH_CIGAM_64)) {
file_architecture = OSSwapInt32(file_architecture);
}
if (x86_64_CPU && (file_architecture == CPU_TYPE_I386)) {
// Single-architecture i386 file on x86_64 CPU
if (compareOSVersionTo(10, 15) < 0) {
// OS >= 10.15 are 64-bit only
retval = true;
}
} else if (x86_64_CPU && (file_architecture == CPU_TYPE_X86_64)) {
retval = true; // Single-architecture x86_64 file on x86_64 CPU
} else if (arm64_cpu && (file_architecture == CPU_TYPE_ARM64)) {
retval = true; // Single-architecture arm64 file on arm64 CPU
} else if (arm64_cpu && (file_architecture == CPU_TYPE_X86_64)) {
retval = true; // Single-architecture x86_64 file emulated on arm64 CPU
// TODO: determine whether emulated graphics apps work properly
}
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
}
file_architecture = fatHeader.cputype;
if (theMagic == FAT_CIGAM) {
file_architecture = OSSwapInt32(file_architecture);
}
if (x86_64_CPU && (file_architecture == CPU_TYPE_X86_64)) {
retval = true; // file with x86_64 architecture on x86_64 CPU
break;
} else if (arm64_cpu && (file_architecture == CPU_TYPE_ARM64)) {
retval = true; // file with arm64 architecture on arm64 CPU
break;
} else if (arm64_cpu && (file_architecture == CPU_TYPE_X86_64)) {
retval = true; // file with x86_64 architecture emulated on arm64 CPU
// TODO: determine whether emulated graphics apps work properly
}
}
break;
default:
break;
}
fclose (f);
return retval;
}
#endif

View File

@ -184,7 +184,7 @@ enum BATTERY_STATE {
// some output file permanent failure
// Values of FILE_INFO::status.
// If the status is neither of these two,
// If the status is none of these,
// it's an error code indicating an unrecoverable error
// in the transfer of the file,
// or that the file was too big and was deleted.

View File

@ -150,12 +150,14 @@ public:
extern void make_secure_random_string(char*);
#ifdef _WIN64
int get_wsl_information(bool& wsl_available, WSLS& wsls);
int get_processor_group(HANDLE);
extern int get_wsl_information(bool& wsl_available, WSLS& wsls);
extern int get_processor_group(HANDLE);
#endif
#ifdef __APPLE__
int get_system_uptime();
extern int get_system_uptime();
extern bool can_run_on_this_CPU(char* exec_path);
// can the app run on this CPU architecture?
#ifdef __cplusplus
extern "C" {
@ -165,7 +167,7 @@ extern "C" {
#include <IOKit/hidsystem/IOHIDParameter.h>
#include <IOKit/hidsystem/event_status_driver.h>
bool isDualGPUMacBook();
extern bool isDualGPUMacBook();
// Apple has removed NxIdleTime() beginning with OS 10.6, so we must try
// loading it at run time to avoid a link error. For details, please see