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