diff --git a/client/app.cpp b/client/app.cpp index 4ab383e6bc..4111e1b959 100644 --- a/client/app.cpp +++ b/client/app.cpp @@ -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( " %s\n" @@ -767,6 +771,7 @@ int ACTIVE_TASK::write_gui(MIOFILE& fout) { slot_path ); } + if (strlen(web_graphics_url)) { fout.printf( " %s\n", diff --git a/client/client_state.cpp b/client/client_state.cpp index 0e1fa872d7..072b4fa210 100644 --- a/client/client_state.cpp +++ b/client/client_state.cpp @@ -15,17 +15,6 @@ // You should have received a copy of the GNU Lesser General Public License // along with BOINC. If not, see . -#ifdef __APPLE__ -#include -#include -#include -#include -#include -#include - -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= 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; diff --git a/client/client_types.h b/client/client_types.h index 219ef7f95f..1f224e798c 100644 --- a/client/client_types.h +++ b/client/client_types.h @@ -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 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 { diff --git a/client/hostinfo_unix.cpp b/client/hostinfo_unix.cpp index 2cf9af3a18..779aa16a68 100644 --- a/client/hostinfo_unix.cpp +++ b/client/hostinfo_unix.cpp @@ -124,6 +124,14 @@ using std::min; #include #include #include +#include +#include +#include +#include +#include +#include + +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 #include -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