[boinc] 01/01: New upstream version 7.8.3+dfsg
Gianfranco Costamagna
locutusofborg at moszumanska.debian.org
Thu Oct 5 09:24:51 UTC 2017
This is an automated email from the git hooks/post-receive script.
locutusofborg pushed a commit to branch upstream
in repository boinc.
commit dbf44b51f8ce3294dca39505e6653de042171aaf
Author: Gianfranco Costamagna <costamagnagianfranco at yahoo.it>
Date: Thu Oct 5 11:10:57 2017 +0200
New upstream version 7.8.3+dfsg
---
api/MultiGPUMig.defs | 19 ++
api/graphics2.cpp | 21 +-
api/graphics2_unix.cpp | 52 +++-
api/macglutfix.m | 355 +++++++++++++++++++++++++-
api/x_opengl.h | 10 +-
client/acct_mgr.cpp | 115 ++++++---
client/app_control.cpp | 14 +-
client/app_start.cpp | 4 +-
client/async_file.cpp | 6 +-
client/client_state.cpp | 59 ++---
client/client_state.h | 2 +-
client/cpu_sched.cpp | 6 +-
client/project.cpp | 8 +-
client/project.h | 8 +-
clientscr/Mac_Saver_Module.h | 33 ++-
clientscr/Mac_Saver_ModuleView.h | 40 ++-
clientscr/Mac_Saver_ModuleView.m | 530 +++++++++++++++++++++++++++++++++++----
clientscr/mac_saver_module.cpp | 62 ++++-
clientscr/screensaver.cpp | 68 ++++-
clientscr/screensaver.h | 3 +-
configure.ac | 2 +-
lib/cc_config.cpp | 4 +-
lib/filesys.cpp | 4 +-
locale/fr/BOINC-Manager.mo | Bin 80627 -> 80651 bytes
version.log | 2 +-
25 files changed, 1244 insertions(+), 183 deletions(-)
diff --git a/api/MultiGPUMig.defs b/api/MultiGPUMig.defs
new file mode 100644
index 0000000..00f1424
--- /dev/null
+++ b/api/MultiGPUMig.defs
@@ -0,0 +1,19 @@
+#include <mach/mach_types.defs>
+
+subsystem MGSServer 29000;
+userprefix _MGC; /* Routine prefixes for user access. */
+serverprefix _MGS; /* Routine prefixes for internal server access. */
+
+/* Client -> Server */
+routine CheckinClient(
+ server_port : mach_port_t;
+ in client_port : mach_port_t;
+ out client_index : int32_t
+);
+
+/* Master -> Slave */
+routine DisplayFrame(
+ server_port : mach_port_t;
+ frame_index : int32_t;
+ iosurface_port : mach_port_t
+);
diff --git a/api/graphics2.cpp b/api/graphics2.cpp
index 56b0fa9..d72d7bd 100644
--- a/api/graphics2.cpp
+++ b/api/graphics2.cpp
@@ -1,6 +1,6 @@
// This file is part of BOINC.
// http://boinc.berkeley.edu
-// Copyright (C) 2008 University of California
+// Copyright (C) 2017 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
@@ -31,6 +31,9 @@
#include "shmem.h"
#include "boinc_api.h"
#include "graphics2.h"
+#ifdef __APPLE__
+#include "x_opengl.h"
+#endif
double boinc_max_fps = 30.;
double boinc_max_gfx_cpu_frac = 0.2;
@@ -84,7 +87,23 @@ bool throttled_app_render(int x, int y, double t) {
if (boinc_max_gfx_cpu_frac) {
boinc_calling_thread_cpu_time(t0);
}
+
+#ifdef __APPLE__
+ if (UseSharedOffscreenBuffer()) {
+ MacPrepareOffscreenBuffer();
+ }
+#endif
app_graphics_render(x, y, t);
+
+#ifdef __APPLE__
+ if (UseSharedOffscreenBuffer()) {
+ MacPassOffscreenBufferToScreenSaver();
+
+//app_graphics_render(x, y, t); // For testing only
+ }
+
+#endif
+
if (boinc_max_gfx_cpu_frac) {
boinc_calling_thread_cpu_time(t1);
total_render_time += t1 - t0;
diff --git a/api/graphics2_unix.cpp b/api/graphics2_unix.cpp
index 63f6c77..4659d44 100644
--- a/api/graphics2_unix.cpp
+++ b/api/graphics2_unix.cpp
@@ -1,6 +1,6 @@
// This file is part of BOINC.
// http://boinc.berkeley.edu
-// Copyright (C) 2008 University of California
+// Copyright (C) 2017 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
@@ -118,6 +118,11 @@ static void maybe_render() {
if (throttled_app_render(new_width, new_height, dtime())) {
+#ifdef __APPLE__
+ if (UseSharedOffscreenBuffer()) {
+ return; // Don't try to send garbage to screen
+ }
+#endif
glutSwapBuffers();
if (! fullscreen) {
// If user has changed window size, wait until it stops
@@ -244,3 +249,48 @@ void boinc_graphics_loop(int argc, char** argv, const char* title) {
#endif
glutMainLoop();
}
+
+#ifdef __APPLE__
+
+bool UseSharedOffscreenBuffer() {
+ static bool alreadyTested = false;
+ static bool needSharedGfxBuffer = false;
+
+//return true; // FOR TESTING ONLY
+ if (alreadyTested) {
+ return needSharedGfxBuffer;
+ }
+ alreadyTested = true;
+ if (fullscreen) {
+ SInt32 major = -1;
+ SInt32 minor = -1;
+ char vers[100], *p1 = NULL;
+ FILE *f;
+ vers[0] = '\0';
+ f = popen("sw_vers -productVersion", "r");
+ if (f) {
+ fscanf(f, "%s", vers);
+ pclose(f);
+ }
+ if (vers[0] == '\0') {
+ fprintf(stderr, "popen(\"sw_vers -productVersion\" failed\n");
+ fflush(stderr);
+ return false;
+ }
+ // Extract the major system version number
+ major = atoi(vers);
+ if (major > 10) { // OS 11.0 or later
+ needSharedGfxBuffer = true;
+ return true;
+ }
+ // Extract the minor system version number
+ p1 = strchr(vers, '.');
+ minor = atoi(p1+1);
+ if (minor > 12) { // OS 10.13 or later
+ needSharedGfxBuffer = true;
+ return true;
+ }
+ }
+ return false;
+}
+#endif
diff --git a/api/macglutfix.m b/api/macglutfix.m
index 69d4ba5..08070ef 100644
--- a/api/macglutfix.m
+++ b/api/macglutfix.m
@@ -1,6 +1,6 @@
// Berkeley Open Infrastructure for Network Computing
// http://boinc.berkeley.edu
-// Copyright (C) 2005 University of California
+// Copyright (C) 2017 University of California
//
// This is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
@@ -21,13 +21,30 @@
// macglutfix.m
//
+#define CREATE_LOG 0 // Set to 1 for debugging
+
+#define GL_DO_NOT_WARN_IF_MULTI_GL_VERSION_HEADERS_INCLUDED
+
#include <Cocoa/Cocoa.h>
+#include <mach/mach_time.h>
+#include <pthread.h>
+#import <OpenGL/CGLIOSurface.h>
+#import <GLKit/GLKit.h>
+#include <servers/bootstrap.h>
+#import "MultiGPUMig.h"
+#import "MultiGPUMigServer.h"
+#include "x_opengl.h"
+#include "boinc_gl.h"
+#include "boinc_glut.h"
+
+extern bool fullscreen; // set in graphics2_unix.cpp
// For unknown reason, "boinc_api.h" gets a compile
// error here so just declare boinc_is_standalone()
//#include "boinc_api.h"
extern int boinc_is_standalone(void);
+// int set_realtime(int period, int computation, int constraint);
void MacGLUTFix(bool isScreenSaver);
void BringAppToFront(void);
@@ -54,11 +71,6 @@ void MacGLUTFix(bool isScreenSaver) {
}
}
- // In screensaver mode, set our window's level just above
- // our BOINC screensaver's window level so it can appear
- // over it. This doesn't interfere with the screensaver
- // password dialog because the dialog appears only after
- // our screensaver is closed.
myContext = [ NSOpenGLContext currentContext ];
if (myContext)
myView = [ myContext view ];
@@ -66,17 +78,57 @@ void MacGLUTFix(bool isScreenSaver) {
myWindow = [ myView window ];
if (myWindow == nil)
return;
-
+
if (!isScreenSaver) {
NSButton *closeButton = [myWindow standardWindowButton:NSWindowCloseButton ];
[closeButton setEnabled:YES];
[myWindow setDocumentEdited: NO];
return;
}
-
- if ([ myWindow level ] == GlutFullScreenWindowLevel)
- [ myWindow setLevel:RealSaverLevel+20 ];
+
+ // As of OS 10.13, app windows can no longer appear on top of screensaver
+ // window, but we still use this method on older versions of OS X for
+ // compatibility with older project graphics apps.
+ if (!UseSharedOffscreenBuffer()) {
+ // In screensaver mode, set our window's level just above
+ // our BOINC screensaver's window level so it can appear
+ // over it. This doesn't interfere with the screensaver
+ // password dialog because the dialog appears only after
+ // our screensaver is closed.
+ if ([ myWindow level ] == GlutFullScreenWindowLevel) {
+ [ myWindow setLevel:RealSaverLevel+20 ];
+ }
+ }
+}
+
+#if 0
+// NOT USED: See comments in animateOneFrame in Mac_Saver_ModuleView.m
+// <https://developer.apple.com/library/content/technotes/tn2169>
+int set_realtime(int period, int computation, int constraint) {
+ mach_timebase_info_data_t timebase_info;
+ mach_timebase_info(&timebase_info);
+
+ const uint64_t NANOS_PER_MSEC = 1000000ULL;
+ double clock2abs = ((double)timebase_info.denom / (double)timebase_info.numer) * NANOS_PER_MSEC;
+
+ thread_time_constraint_policy_data_t policy;
+ policy.period = period;
+ policy.computation = (uint32_t)(computation * clock2abs); // computation ms of work
+ policy.constraint = (uint32_t)(constraint * clock2abs);
+// policy.preemptible = FALSE;
+ policy.preemptible = TRUE;
+
+ int kr = thread_policy_set(pthread_mach_thread_np(pthread_self()),
+ THREAD_TIME_CONSTRAINT_POLICY,
+ (thread_policy_t)&policy,
+ THREAD_TIME_CONSTRAINT_POLICY_COUNT);
+ if (kr != KERN_SUCCESS) {
+ fprintf(stderr, "set_realtime() failed.\n");
+ return 0;
+ }
+ return 1;
}
+#endif
void BringAppToFront() {
[ NSApp activateIgnoringOtherApps:YES ];
@@ -86,3 +138,286 @@ void HideThisApp() {
[ NSApp hide:NSApp ];
}
+// On OS 10.13 or later, use MachO comunication and IOSurfaceBuffer to
+// display the graphics output of our child graphics apps in our window.
+
+// Code adapted from Apple Developer Tech Support Sample Code MutiGPUIOSurface:
+// <https://developer.apple.com/library/content/samplecode/MultiGPUIOSurface>
+
+#define NUM_IOSURFACE_BUFFERS 2
+
+ at interface ServerController : NSObject <NSMachPortDelegate>
+{
+ NSMachPort *serverPort;
+ NSMachPort *localPort;
+
+ uint32_t serverPortName;
+ uint32_t localPortName;
+
+ NSMachPort *clientPort[16];
+ uint32_t clientPortNames[16];
+ uint32_t clientPortCount;
+}
+- (ServerController *)init;
+- (kern_return_t)checkInClient:(mach_port_t)client_port index:(int32_t *)client_index;
+- (void)portDied:(NSNotification *)notification;
+- (void)sendIOSurfaceMachPortToClients: (uint32_t)index withMachPort:(mach_port_t) iosurface_port;
+
+ at end
+
+static ServerController *myserverController;
+
+static uint32_t nextFrameIndex;
+static uint32_t currentFrameIndex;
+
+static IOSurfaceRef ioSurfaceBuffers[NUM_IOSURFACE_BUFFERS];
+static mach_port_t ioSurfaceMachPorts[NUM_IOSURFACE_BUFFERS];
+static GLuint textureNames[NUM_IOSURFACE_BUFFERS];
+static GLuint fboNames[NUM_IOSURFACE_BUFFERS];
+static GLuint depthBufferName;
+
+ at implementation ServerController
+
+- (ServerController *)init
+{
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(portDied:) name:NSPortDidBecomeInvalidNotification object:nil];
+
+ mach_port_t servicePortNum = MACH_PORT_NULL;
+ kern_return_t machErr;
+ char *portName = "edu.berkeley.boincsaver";
+
+// NSMachBootstrapServer is deprecated in OS 10.13, so use bootstrap_look_up
+// serverPort = [(NSMachPort *)([[NSMachBootstrapServer sharedInstance] servicePortWithName:@"edu.berkeley.boincsaver"]) retain];
+ machErr = bootstrap_check_in(bootstrap_port, portName, &servicePortNum);
+ if (machErr != KERN_SUCCESS) {
+ [NSApp terminate:self];
+ }
+ serverPort = (NSMachPort*)[NSMachPort portWithMachPort:servicePortNum];
+
+ // Create a local dummy reply port to use with the mig reply stuff
+ localPort = [[NSMachPort alloc] init];
+
+ // Retrieve raw mach port names.
+ serverPortName = [serverPort machPort];
+ localPortName = [localPort machPort];
+
+ [serverPort setDelegate:self];
+ [serverPort scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
+
+ // NOT USED: See comments in animateOneFrame in Mac_Saver_ModuleView.m
+#if 0
+ // This is an alternate method to get enough CPU cycles when we
+ // are running in the background behind ScreensaverEngine.app
+ set_realtime(0, 5, 33);
+ //set_realtime(0, 5, 10);
+ //set_realtime(33, 5, 33);
+ //set_realtime(30, 3, 6);
+ //set_realtime(30, 10, 20);
+#endif
+
+ return self;
+}
+
+- (void)portDied:(NSNotification *)notification
+{
+ NSPort *port = [notification object];
+ if(port == serverPort)
+ {
+ [NSApp terminate:self];
+ }
+ else
+ {
+ int i;
+ for(i = 0; i < clientPortCount+1; i++)
+ {
+ if([clientPort[i] isEqual:port])
+ {
+ [clientPort[i] release];
+ clientPort[i] = nil;
+ clientPortNames[i] = 0;
+ }
+ }
+ }
+}
+
+- (void)handleMachMessage:(void *)msg
+{
+ union __ReplyUnion___MGCMGSServer_subsystem reply;
+
+ mach_msg_header_t *reply_header = (void *)&reply;
+ kern_return_t kr;
+
+ if(MGSServer_server(msg, reply_header) && reply_header->msgh_remote_port != MACH_PORT_NULL)
+ {
+ kr = mach_msg(reply_header, MACH_SEND_MSG, reply_header->msgh_size, 0, MACH_PORT_NULL,
+ 0, MACH_PORT_NULL);
+ if(kr != 0)
+ [NSApp terminate:nil];
+ }
+}
+
+- (kern_return_t)checkInClient:(mach_port_t)client_port index:(int32_t *)client_index
+{
+ clientPortCount++; // clients always start at index 1
+ clientPortNames[clientPortCount] = client_port;
+ clientPort[clientPortCount] = [[NSMachPort alloc] initWithMachPort:client_port];
+
+ *client_index = clientPortCount;
+ return 0;
+}
+
+kern_return_t _MGSCheckinClient(mach_port_t server_port, mach_port_t client_port,
+ int32_t *client_index)
+{
+ return [myserverController checkInClient:client_port index:client_index];
+}
+
+// For the MachO server, this is a no-op
+kern_return_t _MGSDisplayFrame(mach_port_t server_port, int32_t frame_index, uint32_t iosurface_port)
+{
+ return 0;
+}
+
+- (void)sendIOSurfaceMachPortToClients:(uint32_t)index withMachPort:(mach_port_t)iosurface_port
+{
+ int i;
+ for(i = 0; i < clientPortCount+1; i++)
+ {
+ if(clientPortNames[i])
+ {
+ // print_to_log_file("BOINCSCR: about to call _MGCDisplayFrame with iosurface_port %d, IOSurfaceGetID %d and frameIndex %d", (int)iosurface_port, IOSurfaceGetID(ioSurfaceBuffers[index]), (int)index);
+ _MGCDisplayFrame(clientPortNames[i], index, iosurface_port);
+ }
+ }
+}
+ at end
+
+
+void MacPrepareOffscreenBuffer() {
+ GLuint name, namef;
+
+ if (!myserverController) {
+ myserverController = [[[ServerController alloc] init] retain];
+ }
+
+ if (!ioSurfaceBuffers[0]) {
+ NSOpenGLContext * myContext = [ NSOpenGLContext currentContext ];
+ NSView *myView = [ myContext view ];
+ GLsizei w = myView.bounds.size.width;
+ GLsizei h = myView.bounds.size.height;
+
+ // Set up all of our iosurface buffers
+ for(int i = 0; i < NUM_IOSURFACE_BUFFERS; i++) {
+ ioSurfaceBuffers[i] = IOSurfaceCreate((CFDictionaryRef)@{
+ (id)kIOSurfaceWidth: [NSNumber numberWithInt: w],
+ (id)kIOSurfaceHeight: [NSNumber numberWithInt: h],
+ (id)kIOSurfaceBytesPerElement: @4
+ });
+ ioSurfaceMachPorts[i] = IOSurfaceCreateMachPort(ioSurfaceBuffers[i]);
+ }
+ }
+
+ if(!textureNames[nextFrameIndex])
+ {
+ NSOpenGLContext * myContext = [ NSOpenGLContext currentContext ];
+ NSView *myView = [ myContext view ];
+ GLsizei w = myView.bounds.size.width;
+ GLsizei h = myView.bounds.size.height;
+
+ CGLContextObj cgl_ctx = (CGLContextObj)[myContext CGLContextObj];
+
+ glGenTextures(1, &name);
+
+ glBindTexture(GL_TEXTURE_RECTANGLE, name);
+ // At the moment, CGLTexImageIOSurface2D requires the GL_TEXTURE_RECTANGLE target
+ CGLTexImageIOSurface2D(cgl_ctx, GL_TEXTURE_RECTANGLE, GL_RGBA, w, h, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
+ ioSurfaceBuffers[nextFrameIndex], 0);
+ glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ // Generate an FBO and bind the texture to it as a render target.
+ glBindTexture(GL_TEXTURE_RECTANGLE, 0);
+
+ glGenFramebuffers(1, &namef);
+ glBindFramebuffer(GL_FRAMEBUFFER, namef);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE, name, 0);
+
+ if(!depthBufferName)
+ {
+ glGenRenderbuffers(1, &depthBufferName);
+ glRenderbufferStorage(GL_TEXTURE_RECTANGLE, GL_DEPTH, w, h);
+ }
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_RECTANGLE, depthBufferName);
+
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+ fboNames[nextFrameIndex] = namef;
+ textureNames[nextFrameIndex] = name;
+ }
+ currentFrameIndex = nextFrameIndex;
+ nextFrameIndex = (nextFrameIndex + 1) % NUM_IOSURFACE_BUFFERS;
+
+ glBindFramebuffer(GL_FRAMEBUFFER, fboNames[currentFrameIndex]);
+}
+
+void MacPassOffscreenBufferToScreenSaver() {
+ glutSwapBuffers();
+ [myserverController sendIOSurfaceMachPortToClients: currentFrameIndex
+ withMachPort:ioSurfaceMachPorts[currentFrameIndex]];
+ glFlush();
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+}
+
+// Code for debugging:
+
+#if CREATE_LOG
+void strip_cr(char *buf)
+{
+ char *theCR;
+
+ theCR = strrchr(buf, '\n');
+ if (theCR)
+ *theCR = '\0';
+ theCR = strrchr(buf, '\r');
+ if (theCR)
+ *theCR = '\0';
+}
+#endif
+
+void print_to_log_file(const char *format, ...) {
+#if CREATE_LOG
+ va_list args;
+ char buf[256];
+ time_t t;
+ FILE *f;
+ if (fullscreen) {
+ // We can't write to our home directory if running as user / group boinc_project
+ f = fopen("/Users/Shared/test_log.txt", "a");
+ } else {
+ strlcpy(buf, getenv("HOME"), sizeof(buf));
+ strlcat(buf, "/Documents/test_log.txt", sizeof(buf));
+ f = fopen(buf, "a");
+ // freopen(buf, "a", stdout);
+ //freopen(buf, "a", stderr);
+ }
+ if (!f) return;
+ time(&t);
+ strcpy(buf, asctime(localtime(&t)));
+ strip_cr(buf);
+
+ fputs(buf, f);
+ fputs(" ", f);
+
+ va_start(args, format);
+ vfprintf(f, format, args);
+ va_end(args);
+
+ fputs("\n", f);
+ fflush(f);
+ fclose(f);
+#endif
+}
+
diff --git a/api/x_opengl.h b/api/x_opengl.h
index 55a995e..bb38cee 100644
--- a/api/x_opengl.h
+++ b/api/x_opengl.h
@@ -1,6 +1,6 @@
// This file is part of BOINC.
// http://boinc.berkeley.edu
-// Copyright (C) 2008 University of California
+// Copyright (C) 2017 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
@@ -25,9 +25,15 @@ extern "C" {
extern int xwin_glut_is_initialized();
#ifdef __APPLE__
-extern void MacGLUTFix(bool isScreenSaver);
+extern void MacGLUTFix(bool isScreenSaver);
+extern void MacPrepareOffscreenBuffer(void);
+extern void MacPassOffscreenBufferToScreenSaver(void);
extern void BringAppToFront(void);
extern void HideThisApp(void);
+extern bool UseSharedOffscreenBuffer(void);
+
+extern void print_to_log_file(const char *format, ...);
+
#endif
#ifdef __cplusplus
diff --git a/client/acct_mgr.cpp b/client/acct_mgr.cpp
index 1064b75..af9d1cc 100644
--- a/client/acct_mgr.cpp
+++ b/client/acct_mgr.cpp
@@ -170,7 +170,9 @@ int ACCT_MGR_OP::do_rpc(
" <gpu_ec>%f</gpu_ec>\n"
" <gpu_time>%f</gpu_time>\n"
" <njobs_success>%d</njobs_success>\n"
- " <njobs_error>%d</njobs_error>\n",
+ " <njobs_error>%d</njobs_error>\n"
+ " <disk_usage>%f</disk_usage>\n"
+ " <disk_share>%f</disk_share>\n",
p->master_url,
p->project_name,
p->suspended_via_gui?1:0,
@@ -187,7 +189,9 @@ int ACCT_MGR_OP::do_rpc(
p->gpu_ec,
p->gpu_time,
p->njobs_success,
- p->njobs_error
+ p->njobs_error,
+ p->disk_usage,
+ p->disk_share
);
if (p->attached_via_acct_mgr) {
fprintf(f,
@@ -458,54 +462,61 @@ void ACCT_MGR_OP::handle_reply(int http_op_retval) {
bool verified;
PROJECT* pp;
bool sig_ok;
+ bool got_error = false;
- if (http_op_retval == 0) {
+ // check for failures of HTTP OP, reply parse
+ //
+ if (http_op_retval) {
+ msg_printf(&ami, MSG_INFO, "AM RPC HTTP failure: %s",
+ boincerror(http_op_retval)
+ );
+ got_error = true;
+ } else {
FILE* f = fopen(ACCT_MGR_REPLY_FILENAME, "r");
if (f) {
retval = parse(f);
+ if (retval) {
+ got_error = true;
+ msg_printf(&ami, MSG_INFO, "AM reply parse error");
+ }
fclose(f);
} else {
- retval = ERR_FOPEN;
+ msg_printf(&ami, MSG_INFO, "AM reply file missing");
+ got_error = true;
}
- } else {
- error_num = http_op_retval;
}
- gstate.acct_mgr_info.password_error = false;
- if (error_num == ERR_BAD_PASSWD && !via_gui) {
- gstate.acct_mgr_info.password_error = true;
- }
- // check both error_str and error_num since an account manager may only
- // return a BOINC based error code for password failures or invalid
- // email addresses
+ // if no errors so far, check for errors from AM
//
- if (error_str.size()) {
- msg_printf(&ami, MSG_USER_ALERT,
- "%s: %s",
- _("Message from account manager"),
- error_str.c_str()
- );
- if (!error_num) {
- error_num = ERR_XML_PARSE;
- }
- } else if (error_num) {
- if (error_num == http_op_retval) {
- // if it was an HTTP error, don't notify the user;
- // probably the acct mgr server is down
- //
- msg_printf(&ami, MSG_INFO,
- "Account manager RPC failed: %s", boincerror(error_num)
+ if (!got_error) {
+ gstate.acct_mgr_info.password_error = false;
+ if (error_num == ERR_BAD_PASSWD && !via_gui) {
+ gstate.acct_mgr_info.password_error = true;
+ }
+
+ // Show error message from AM if available.
+ // check both error_str and error_num since an account manager may only
+ // return a BOINC based error code for password failures or invalid
+ // email addresses
+ //
+ if (error_str.size()) {
+ msg_printf(&ami, MSG_USER_ALERT,
+ "%s: %s",
+ _("Message from account manager"),
+ error_str.c_str()
);
- } else {
+ got_error = true;
+ } else if (error_num) {
msg_printf(&ami, MSG_USER_ALERT,
"%s: %s",
_("Message from account manager"),
boincerror(error_num)
);
+ got_error = true;
}
}
- if (error_num) {
+ if (got_error) {
gstate.acct_mgr_info.next_rpc_time =
gstate.now
+ calculate_exponential_backoff(
@@ -516,6 +527,26 @@ void ACCT_MGR_OP::handle_reply(int http_op_retval) {
gstate.acct_mgr_info.nfailures++;
return;
}
+
+ // The RPC was successful
+ //
+ // Detach projects that are
+ // - detach_when_done
+ // - done
+ // - attached via AM
+ //
+ while (1) {
+ bool found = false;
+ for (i=0; i<gstate.projects.size(); i++) {
+ PROJECT* p = gstate.projects[i];
+ if (p->detach_when_done && !gstate.nresults_for_project(p) && p->attached_via_acct_mgr) {
+ gstate.detach_project(p);
+ found = true;
+ }
+ }
+ if (!found) break;
+ }
+
gstate.acct_mgr_info.nfailures = 0;
msg_printf(NULL, MSG_INFO, "Account manager contact succeeded");
@@ -562,15 +593,6 @@ void ACCT_MGR_OP::handle_reply(int http_op_retval) {
//
for (i=0; i<accounts.size(); i++) {
AM_ACCOUNT& acct = accounts[i];
- retval = check_string_signature2(
- acct.url.c_str(), acct.url_signature, ami.signing_key, verified
- );
- if (retval || !verified) {
- msg_printf(NULL, MSG_INTERNAL_ERROR,
- "Bad signature for URL %s", acct.url.c_str()
- );
- continue;
- }
pp = gstate.lookup_project(acct.url.c_str());
if (pp) {
if (acct.detach) {
@@ -606,12 +628,16 @@ void ACCT_MGR_OP::handle_reply(int http_op_retval) {
pp->attached_via_acct_mgr = true;
if (acct.dont_request_more_work.present) {
pp->dont_request_more_work = acct.dont_request_more_work.value;
+ } else {
+ pp->dont_request_more_work = false;
}
if (acct.detach_when_done.present) {
pp->detach_when_done = acct.detach_when_done.value;
if (pp->detach_when_done) {
pp->dont_request_more_work = true;
}
+ } else {
+ pp->detach_when_done = false;
}
// initiate a scheduler RPC if requested by AMS
@@ -661,6 +687,15 @@ void ACCT_MGR_OP::handle_reply(int http_op_retval) {
} else {
// here we don't already have the project.
//
+ retval = check_string_signature2(
+ acct.url.c_str(), acct.url_signature, ami.signing_key, verified
+ );
+ if (retval || !verified) {
+ msg_printf(NULL, MSG_INTERNAL_ERROR,
+ "Bad signature for URL %s", acct.url.c_str()
+ );
+ continue;
+ }
if (acct.authenticator.empty()) {
msg_printf(NULL, MSG_INFO,
"Account manager reply missing authenticator for %s",
diff --git a/client/app_control.cpp b/client/app_control.cpp
index 24009b4..b65f2bb 100644
--- a/client/app_control.cpp
+++ b/client/app_control.cpp
@@ -439,6 +439,7 @@ void ACTIVE_TASK::handle_exited_app(int stat) {
);
}
#endif
+ char err_msg[4096];
bool will_restart = false;
get_app_status_msg();
@@ -491,12 +492,12 @@ void ACTIVE_TASK::handle_exited_app(int stat) {
default:
char szError[1024];
set_task_state(PROCESS_EXITED, "handle_exited_app");
- gstate.report_result_error(
- *result,
+ sprintf(err_msg,
"%s - exit code %d (0x%x)",
windows_format_error_string(exit_code, szError, sizeof(szError)),
exit_code, exit_code
);
+ gstate.report_result_error(*result, err_msg);
if (log_flags.task_debug) {
msg_printf(result->project, MSG_INFO,
"[task] Process for %s exited",
@@ -528,12 +529,12 @@ void ACTIVE_TASK::handle_exited_app(int stat) {
}
if (result->exit_status) {
set_task_state(PROCESS_EXITED, "handle_exited_app");
- gstate.report_result_error(
- *result,
+ sprintf(err_msg,
"process exited with code %d (0x%x, %d)",
result->exit_status, result->exit_status,
(-1<<8)|result->exit_status
);
+ gstate.report_result_error(*result, err_msg);
} else {
if (finish_file_present()) {
set_task_state(PROCESS_EXITED, "handle_exited_app");
@@ -567,9 +568,8 @@ void ACTIVE_TASK::handle_exited_app(int stat) {
result->exit_status = stat;
set_task_state(PROCESS_WAS_SIGNALED, "handle_exited_app");
signal = got_signal;
- gstate.report_result_error(
- *result, "process got signal %d", signal
- );
+ sprintf(err_msg, "process got signal %d", signal);
+ gstate.report_result_error(*result, err_msg);
}
} else {
result->exit_status = EXIT_UNKNOWN;
diff --git a/client/app_start.cpp b/client/app_start.cpp
index b0529d9..32eab51 100644
--- a/client/app_start.cpp
+++ b/client/app_start.cpp
@@ -1166,7 +1166,9 @@ error:
// Verify it to trigger another download.
//
gstate.input_files_available(result, true);
- gstate.report_result_error(*result, "couldn't start app: %s", buf);
+ char err_msg[4096];
+ sprintf(err_msg, "couldn't start app: %s", buf);
+ gstate.report_result_error(*result, err_msg);
if (log_flags.task_debug) {
msg_printf(wup->project, MSG_INFO,
"[task] couldn't start app: %s", buf
diff --git a/client/async_file.cpp b/client/async_file.cpp
index e433466..c2c6071 100644
--- a/client/async_file.cpp
+++ b/client/async_file.cpp
@@ -158,10 +158,10 @@ int ASYNC_COPY::copy_chunk() {
// handle the failure of a copy; error out the result
//
void ASYNC_COPY::error(int retval) {
+ char err_msg[4096];
atp->set_task_state(PROCESS_COULDNT_START, "ASYNC_COPY::error");
- gstate.report_result_error(
- *(atp->result), "Couldn't copy file: %s", boincerror(retval)
- );
+ sprintf(err_msg, "Couldn't copy file: %s", boincerror(retval));
+ gstate.report_result_error(*(atp->result), err_msg);
gstate.request_schedule_cpus("start failed");
}
diff --git a/client/client_state.cpp b/client/client_state.cpp
index a087716..f06da49 100644
--- a/client/client_state.cpp
+++ b/client/client_state.cpp
@@ -1416,28 +1416,24 @@ bool CLIENT_STATE::garbage_collect() {
// because detach_project() calls garbage_collect_always(),
// and we need to avoid infinite recursion
//
- if (acct_mgr_info.using_am()) {
- // If we're using an AM,
- // start an AM RPC rather than detaching the projects;
- // the RPC completion handler will detach them.
- // This way the AM will be informed of their work done.
- //
- for (unsigned i=0; i<projects.size(); i++) {
- PROJECT* p = projects[i];
- if (p->detach_when_done && !nresults_for_project(p)) {
- acct_mgr_info.next_rpc_time = 0;
- acct_mgr_info.poll();
- break;
- }
- }
- } else {
+ while (1) {
+ bool found = false;
for (unsigned i=0; i<projects.size(); i++) {
PROJECT* p = projects[i];
if (p->detach_when_done && !nresults_for_project(p)) {
- detach_project(p);
- action = true;
+ // If we're using an AM,
+ // wait until the next successful RPC to detach project,
+ // so the AM will be informed of its work done.
+ //
+ if (!p->attached_via_acct_mgr) {
+ msg_printf(p, MSG_INFO, "Detaching - no more tasks");
+ detach_project(p);
+ action = true;
+ found = true;
+ }
}
}
+ if (!found) break;
}
#endif
return action;
@@ -1545,14 +1541,12 @@ bool CLIENT_STATE::garbage_collect_always() {
wup = rp->wup;
if (wup->had_download_failure(failnum)) {
wup->get_file_errors(error_msgs);
- report_result_error(
- *rp, "WU download error: %s", error_msgs.c_str()
- );
+ string err_msg = "WU download error: " + error_msgs;
+ report_result_error(*rp, err_msg.c_str());
} else if (rp->avp && rp->avp->had_download_failure(failnum)) {
rp->avp->get_file_errors(error_msgs);
- report_result_error(
- *rp, "app_version download error: %s", error_msgs.c_str()
- );
+ string err_msg = "app_version download error: " + error_msgs;
+ report_result_error(*rp, err_msg.c_str());
}
}
bool found_error = false;
@@ -1585,7 +1579,8 @@ bool CLIENT_STATE::garbage_collect_always() {
atp->abort_task(ERR_RESULT_UPLOAD, "upload failure");
}
}
- report_result_error(*rp, "upload failure: %s", error_str.c_str());
+ string err_msg = "upload failure: " + error_str;
+ report_result_error(*rp, err_msg.c_str());
}
#endif
rp->avp->ref_cnt++;
@@ -1835,10 +1830,8 @@ bool CLIENT_STATE::time_to_exit() {
// - If result state is FILES_DOWNLOADED, change it to COMPUTE_ERROR
// so that we don't try to run it again.
//
-int CLIENT_STATE::report_result_error(RESULT& res, const char* format, ...) {
- char buf[4096], err_msg[4096];
- // The above store 1-line messages and short XML snippets.
- // Shouldn't exceed a few hundred bytes.
+int CLIENT_STATE::report_result_error(RESULT& res, const char* err_msg) {
+ char buf[1024];
unsigned int i;
int failnum;
@@ -1851,18 +1844,14 @@ int CLIENT_STATE::report_result_error(RESULT& res, const char* format, ...) {
res.set_ready_to_report();
res.completed_time = now;
- va_list va;
- va_start(va, format);
- vsnprintf(err_msg, sizeof(err_msg), format, va);
- va_end(va);
-
sprintf(buf, "Unrecoverable error for task %s", res.name);
#ifndef SIM
scheduler_op->project_rpc_backoff(res.project, buf);
#endif
- sprintf( buf, "<message>\n%s\n</message>\n", err_msg);
- res.stderr_out.append(buf);
+ res.stderr_out.append("<message>\n");
+ res.stderr_out.append(err_msg);
+ res.stderr_out.append("</message>\n");
switch(res.state()) {
case RESULT_NEW:
diff --git a/client/client_state.h b/client/client_state.h
index 489a5be..d8d574f 100644
--- a/client/client_state.h
+++ b/client/client_state.h
@@ -265,7 +265,7 @@ struct CLIENT_STATE {
APP*, char* platform, int ver, char* plan_class
);
int detach_project(PROJECT*);
- int report_result_error(RESULT&, const char *format, ...);
+ int report_result_error(RESULT&, const char* err_msg);
int reset_project(PROJECT*, bool detaching);
bool no_gui_rpc;
bool gui_rpc_unix_domain;
diff --git a/client/cpu_sched.cpp b/client/cpu_sched.cpp
index 2665bf4..2a3e8ad 100644
--- a/client/cpu_sched.cpp
+++ b/client/cpu_sched.cpp
@@ -1442,9 +1442,9 @@ bool CLIENT_STATE::enforce_run_list(vector<RESULT*>& run_list) {
continue;
}
if (retval) {
- report_result_error(
- *(atp->result), "Couldn't start or resume: %d", retval
- );
+ char err_msg[4096];
+ sprintf(err_msg, "Couldn't start or resume: %d", retval);
+ report_result_error(*(atp->result), err_msg);
request_schedule_cpus("start failed");
continue;
}
diff --git a/client/project.cpp b/client/project.cpp
index e19e952..eab0706 100644
--- a/client/project.cpp
+++ b/client/project.cpp
@@ -332,6 +332,8 @@ int PROJECT::parse_state(XML_PARSER& xp) {
if (xp.parse_double("cpu_time", cpu_time)) continue;
if (xp.parse_double("gpu_ec", gpu_ec)) continue;
if (xp.parse_double("gpu_time", gpu_time)) continue;
+ if (xp.parse_double("disk_usage", disk_usage)) continue;
+ if (xp.parse_double("disk_share", disk_share)) continue;
#ifdef SIM
if (xp.match_tag("available")) {
available.parse(xp, "/available");
@@ -529,8 +531,10 @@ int PROJECT::write_state(MIOFILE& out, bool gui_rpc) {
" <cpu_ec>%f</cpu_ec>\n"
" <cpu_time>%f</cpu_time>\n"
" <gpu_ec>%f</gpu_ec>\n"
- " <gpu_time>%f</gpu_time>\n",
- cpu_ec, cpu_time, gpu_ec, gpu_time
+ " <gpu_time>%f</gpu_time>\n"
+ " <disk_usage>%f</disk_usage>\n"
+ " <disk_share>%f</disk_share>\n",
+ cpu_ec, cpu_time, gpu_ec, gpu_time, disk_usage, disk_share
);
}
out.printf(
diff --git a/client/project.h b/client/project.h
index 3029efe..3c677a2 100644
--- a/client/project.h
+++ b/client/project.h
@@ -153,6 +153,10 @@ struct PROJECT : PROJ_AM {
// Reasons are enumerated in lib/common_defs.h
bool trickle_up_pending;
// have trickle up to send
+ double disk_usage;
+ // computed by get_disk_usages()
+ double disk_share;
+ // computed by get_disk_shares();
/////// END OF ITEMS STORED IN client_state.xml
@@ -174,10 +178,6 @@ struct PROJECT : PROJ_AM {
// to make sure they haven't been tampered with.
// This provides only the illusion of security.
bool use_symlinks;
- double disk_usage;
- // computed by get_disk_usages()
- double disk_share;
- // computed by get_disk_shares();
bool report_results_immediately;
// items sent in scheduler replies,
diff --git a/clientscr/Mac_Saver_Module.h b/clientscr/Mac_Saver_Module.h
index 6334c62..a72b215 100644
--- a/clientscr/Mac_Saver_Module.h
+++ b/clientscr/Mac_Saver_Module.h
@@ -1,6 +1,6 @@
// This file is part of BOINC.
// http://boinc.berkeley.edu
-// Copyright (C) 2008 University of California
+// Copyright (C) 2017 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
@@ -24,6 +24,8 @@
#include <Carbon/Carbon.h>
+// The declarations below must be kept in sync with
+// the corresponding ones in Mac_Saver_ModuleView.h
#ifdef _DEBUG
#define _T(x) x
#endif
@@ -43,12 +45,14 @@ bool getShow_default_ss_first();
double getGFXDefaultPeriod();
double getGFXSciencePeriod();
double getGGFXChangePeriod();
+void incompatibleGfxApp(char * appPath, pid_t pid, int slot);
void setShow_default_ss_first(bool value);
void setGFXDefaultPeriod(double value);
void setGFXSciencePeriod(double value);
void setGGFXChangePeriod(double value);
double getDTime();
void doBoinc_Sleep(double seconds);
+void launchedGfxApp(char * appPath, pid_t thePID, int slot);
void print_to_log_file(const char *format, ...);
void strip_cr(char *buf);
void PrintBacktrace(void);
@@ -57,6 +61,9 @@ void PrintBacktrace(void);
} // extern "C"
#endif
+// The declarations above must be kept in sync with
+// the corresponding ones in Mac_Saver_ModuleView.h
+
struct ss_periods
{
double GFXDefaultPeriod;
@@ -86,8 +93,6 @@ protected:
int GetBrandID(void);
char* PersistentFGets(char *buf, size_t buflen, FILE *f);
pid_t FindProcessPID(char* name, pid_t thePID);
- bool SetError( bool bErrorMode, unsigned int hrError );
- void setSSMessageText(const char *msg);
void updateSSMessageText(char *msg);
void strip_cr(char *buf);
char m_gfx_Switcher_Path[PATH_MAX];
@@ -107,7 +112,7 @@ protected:
bool m_bScience_gfx_running;
bool m_bDefault_gfx_running;
bool m_bConnected;
-
+ std::vector<char*> m_vIncompatibleGfxApps;
//
// Data management layer
//
@@ -118,16 +123,13 @@ protected:
void* DataManagementProc();
static void* DataManagementProcStub( void* param );
int terminate_v6_screensaver(int& graphics_application);
- int terminate_screensaver(int& graphics_application, RESULT *worker_app);
int terminate_default_screensaver(int& graphics_application);
int launch_screensaver(RESULT* rp, int& graphics_application);
int launch_default_screensaver(char *dir_path, int& graphics_application);
void HandleRPCError(void);
int KillScreenSaver(void);
void GetDefaultDisplayPeriods(struct ss_periods &periods);
- bool HasProcessExited(pid_t pid, int &exitCode);
pthread_t m_hDataManagementThread;
- pid_t m_hGraphicsApplication;
// Determine if two RESULT pointers refer to the same task
bool is_same_task(RESULT* taska, RESULT* taskb);
@@ -139,10 +141,6 @@ protected:
// was passed in.
RESULT* get_random_graphics_app(RESULTS& results, RESULT* exclude = NULL);
-
- RPC_CLIENT *rpc;
- CC_STATE state;
- RESULTS results;
bool m_bResetCoreState;
bool m_bQuitDataManagementProc;
@@ -162,12 +160,25 @@ public:
void windowIsCovered(void);
void drawPreview(CGContextRef myContext);
void ShutdownSaver();
+ void markAsIncompatible(char *gfxAppName);
+ bool isIncompatible(char *appName);
+ bool SetError( bool bErrorMode, unsigned int hrError );
+ void setSSMessageText(const char *msg);
+
+ int terminate_screensaver(int& graphics_application, RESULT *worker_app);
+ bool HasProcessExited(pid_t pid, int &exitCode);
+
+ CC_STATE state;
+ RESULTS results;
+ RPC_CLIENT *rpc;
double m_fGFXDefaultPeriod;
double m_fGFXSciencePeriod;
double m_fGFXChangePeriod;
bool m_bShow_default_ss_first;
+ pid_t m_hGraphicsApplication;
+
protected:
};
diff --git a/clientscr/Mac_Saver_ModuleView.h b/clientscr/Mac_Saver_ModuleView.h
index e2a634c..0bf2292 100644
--- a/clientscr/Mac_Saver_ModuleView.h
+++ b/clientscr/Mac_Saver_ModuleView.h
@@ -20,6 +20,7 @@
//
#import <ScreenSaver/ScreenSaver.h>
+#import <Cocoa/Cocoa.h>
@interface BOINC_Saver_ModuleView : ScreenSaverView
@@ -43,19 +44,54 @@
@end
+ at interface SharedGraphicsController : NSObject <NSMachPortDelegate>
+
+ at property (NS_NONATOMIC_IOSONLY, readonly) GLuint currentTextureName;
+- (instancetype)init:(NSView*)saverView;
+- (void)portDied:(NSNotification *)notification;
+- (void)testConnection;
+
+ at end
+
+ at interface saverOpenGLView : NSOpenGLView
+
+- (GLuint)setupIOSurfaceTexture:(IOSurfaceRef)ioSurfaceBuffer;
+
+ at end
+
+// The declarations below must be kept in sync with
+// the corresponding ones in Mac_Saver_Module.h
+#ifdef _DEBUG
+ #define _T(x) x
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
void initBOINCSaver(void);
int startBOINCSaver(void);
int getSSMessage(char **theMessage, int* coveredFreq);
void windowIsCovered();
void drawPreview(CGContextRef myContext);
void closeBOINCSaver(void);
+void setDefaultDisplayPeriods(void);
+bool getShow_default_ss_first();
double getGFXDefaultPeriod();
double getGFXSciencePeriod();
double getGGFXChangePeriod();
+void incompatibleGfxApp(char * appPath, pid_t pid, int slot);
+void setShow_default_ss_first(bool value);
void setGFXDefaultPeriod(double value);
void setGFXSciencePeriod(double value);
void setGGFXChangePeriod(double value);
-bool validateNumericString(CFStringRef s);
double getDTime();
void doBoinc_Sleep(double seconds);
-extern void print_to_log_file(const char *format, ...);
+void launchedGfxApp(char * appPath, pid_t thePID, int slot);
+void print_to_log_file(const char *format, ...);
+void strip_cr(char *buf);
+void PrintBacktrace(void);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/clientscr/Mac_Saver_ModuleView.m b/clientscr/Mac_Saver_ModuleView.m
index 50e36e7..565776a 100644
--- a/clientscr/Mac_Saver_ModuleView.m
+++ b/clientscr/Mac_Saver_ModuleView.m
@@ -20,14 +20,24 @@
// BOINC_Saver_Module
//
+#define GL_DO_NOT_WARN_IF_MULTI_GL_VERSION_HEADERS_INCLUDED 1
+
#import "Mac_Saver_ModuleView.h"
#include <Carbon/Carbon.h>
#include <AppKit/AppKit.h>
-#include <QTKit/QTKitDefines.h> // For NSInteger
#include <IOKit/hidsystem/IOHIDLib.h>
#include <IOKit/hidsystem/IOHIDParameter.h>
#include <IOKit/hidsystem/event_status_driver.h>
+#import <OpenGL/gl.h>
+#import <GLKit/GLKit.h>
+#include <servers/bootstrap.h>
+//#import <IOSurface/IOSurface.h>
+//#import <OpenGL/gl3.h>
+//#import <OpenGL/CGLIOSurface.h>
+
#include "mac_util.h"
+#import "MultiGPUMig.h"
+#import "MultiGPUMigServer.h"
#ifndef NSInteger
#if __LP64__ || NS_BUILD_32_LIKE_64
@@ -59,9 +69,6 @@ typedef float CGFloat;
#define NSAlertStyleCritical NSCriticalAlertStyle
#endif
-void print_to_log_file(const char *format, ...);
-void strip_cr(char *buf);
-
static double gSS_StartTime = 0.0;
mach_port_t gEventHandle = 0;
@@ -85,6 +92,16 @@ NSPoint gCurrentDelta;
CGContextRef myContext;
bool isErased;
+static SharedGraphicsController *mySharedGraphicsController;
+static bool runningSharedGraphics;
+static pid_t childPid;
+static char gfxAppPath[MAXPATHLEN];
+static int taskSlot;
+static NSRunningApplication *childApp;
+static double gfxAppStartTime;
+static bool UseSharedOffscreenBuffer(void);
+
+
#define TEXTBOXMINWIDTH 400.0
#define MINTEXTBOXHEIGHT 40.0
#define MAXTEXTBOXHEIGHT 300.0
@@ -93,10 +110,20 @@ bool isErased;
#define MINDELTA 8
#define MAXDELTA 16
+// On OS 10.13+, assume graphics app is not compatible if no MachO connection after 5 seconds
+#define MAXWAITFORCONNECTION 5.0
+
int signof(float x) {
return (x > 0.0 ? 1 : -1);
}
+void launchedGfxApp(char * appPath, pid_t thePID, int slot) {
+ strlcpy(gfxAppPath, appPath, sizeof(gfxAppPath));
+ childPid = thePID;
+ taskSlot = slot;
+ gfxAppStartTime = getDTime();
+}
+
@implementation BOINC_Saver_ModuleView
- (id)initWithFrame:(NSRect)frame isPreview:(BOOL)isPreview {
@@ -284,6 +311,16 @@ int signof(float x) {
[ self setAnimationTimeInterval:1/30.0 ];
#endif
return;
+ } else {
+ NSWindow *myWindow = [ self window ];
+ NSRect windowFrame = [ myWindow frame ];
+ if ( (windowFrame.origin.x == 0) && (windowFrame.origin.y == 0) ) { // Main screen
+ // On OS 10.13 or later, use MachO comunication and IOSurfaceBuffer to
+ // display the graphics output of our child graphics apps in our window.
+ if (UseSharedOffscreenBuffer() && !mySharedGraphicsController) {
+ mySharedGraphicsController = [[SharedGraphicsController alloc] init:self] ;
+ }
+ }
}
// For unkown reasons, OS 10.7 Lion screensaver and later delay several seconds
@@ -304,59 +341,108 @@ int signof(float x) {
if ( (windowFrame.origin.x != 0) || (windowFrame.origin.y != 0) ) {
// Hide window on second display to aid in debugging
#ifdef _DEBUG
+ // This technique no longer works on newer versions of OS X
[ myWindow setLevel:kCGMinimumWindowLevel ];
NSInteger alpha = 0;
[ myWindow setAlphaValue:alpha ]; // For OS 10.6
+ [ myWindow orderOut:self];
#endif
return; // We draw only to main screen
}
+ // On OS 10.13 or later, use MachO comunication and IOSurfaceBuffer to
+ // display the graphics output of our child graphics apps in our window.
+ if (runningSharedGraphics) {
+ // Since ScreensaverEngine.app is running in the foreground, our child
+ // graphics app may not get enough CPU cycles for good animation.
+ // Calling [ NSApp activateIgnoringOtherApps:YES ] frequently from the
+ // child doesn't help. But activating our child frequently from the
+ // front process (this screensaver plugin) does appear to guarantee
+ // good animation.
+ //
+ // An alternate approach that also works is to have the child process
+ // tell the kernel it has real time constraints by calling
+ // thread_policy_set() with thread_policy_flavor_t set to
+ // THREAD_TIME_CONSTRAINT_POLICY as described in
+ // <https://developer.apple.com/library/content/technotes/tn2169>.
+ //
+ // But different graphics apps may have different time requirements,
+ // so it is difficult to know the best values to set in the
+ // thread_time_constraint_policy_data_t struct. If the graphics app asks
+ // for too much time, the worker apps will get less time, and if it asks
+ // for too little time the animation won't be smooth.
+ //
+ // So frequently activating the child app here seems to be best.
+ //
+ if (childApp) {
+ [ childApp activateWithOptions:NSApplicationActivateIgnoringOtherApps ];\
+ }
+ isErased = false;
+ return;
+ }
+
NSRect viewBounds = [self bounds];
newFrequency = getSSMessage(&msg, &coveredFreq);
- // NOTE: My tests seem to confirm that the top window is always the first
- // window returned by [NSWindow windowNumbersWithOptions:] However, Apple's
- // documentation is unclear whether we can depend on this. So I have
- // added some safety by doing two things:
- // [1] Only use the windowNumbersWithOptions test when we have started
- // project graphics.
- // [2] Assume that our window is covered 45 seconds after starting project
- // graphics even if the windowNumbersWithOptions test did not indicate
- // that is so.
- //
- // getSSMessage() returns a non-zero value for coveredFreq only if we have started
- // project graphics.
- //
- // If we should use a different frequency when our window is covered by another
- // window, then check whether there is a window at a higher z-level than ours.
-
- // Assuming our window(s) are initially the top window(s), determine our position
- // in the window list when no graphics applications have covered us.
- if (gTopWindowListIndex < 0) {
- NSArray *theWindowList = [NSWindow windowNumbersWithOptions:NSWindowNumberListAllApplications];
- myWindowNumber = [ myWindow windowNumber ];
- gTopWindowListIndex = [theWindowList indexOfObjectIdenticalTo:[NSNumber numberWithInt:myWindowNumber]];
- }
-
- if (coveredFreq) {
- if ( (msg != NULL) && (msg[0] != '\0') ) {
+ if (UseSharedOffscreenBuffer()) {
+ // If runningSharedGraphics is still false after MAXWAITFORCONNECTION,
+ // assume graphics app is not compatible with OS 10.13+ and kill it.
+ if (gfxAppStartTime) {
+ if ((getDTime() - gfxAppStartTime)> MAXWAITFORCONNECTION) {
+ incompatibleGfxApp(gfxAppPath, childPid, taskSlot);
+ }
+ }
+ // As of OS 10.13, app windows can no longer appear on top of screensaver
+ // window, but we still use this method on older versions of OS X for
+ // compatibility with older project graphics apps (those which have not
+ // yet been relinked with the updated libboinc_graphics2.a.)
+ } else {
+ // NOTE: My tests seem to confirm that the top window is always the first
+ // window returned by [NSWindow windowNumbersWithOptions:] However, Apple's
+ // documentation is unclear whether we can depend on this. So I have
+ // added some safety by doing two things:
+ // [1] Only use the windowNumbersWithOptions test when we have started
+ // project graphics.
+ // [2] Assume that our window is covered 45 seconds after starting project
+ // graphics even if the windowNumbersWithOptions test did not indicate
+ // that is so.
+ //
+ // getSSMessage() returns a non-zero value for coveredFreq only if we have started
+ // project graphics.
+ //
+ // If we should use a different frequency when our window is covered by another
+ // window, then check whether there is a window at a higher z-level than ours.
+
+ // Assuming our window(s) are initially the top window(s), determine our position
+ // in the window list when no graphics applications have covered us.
+ if (gTopWindowListIndex < 0) {
NSArray *theWindowList = [NSWindow windowNumbersWithOptions:NSWindowNumberListAllApplications];
- n = [theWindowList count];
- if (gTopWindowListIndex < n) {
- if ([(NSNumber*)[theWindowList objectAtIndex:gTopWindowListIndex] integerValue] != myWindowNumber) {
- // Project graphics application has a window open above ours
- // Don't waste CPU cycles since our window is obscured by application graphics
- newFrequency = coveredFreq;
- msg = NULL;
- windowIsCovered();
+ myWindowNumber = [ myWindow windowNumber ];
+ gTopWindowListIndex = [theWindowList indexOfObjectIdenticalTo:[NSNumber numberWithInt:myWindowNumber]];
+ }
+
+ if (coveredFreq) {
+ if ( (msg != NULL) && (msg[0] != '\0') ) {
+ NSArray *theWindowList = [NSWindow windowNumbersWithOptions:NSWindowNumberListAllApplications];
+ n = [theWindowList count];
+ if (gTopWindowListIndex < n) {
+ if ([(NSNumber*)[theWindowList objectAtIndex:gTopWindowListIndex] integerValue] != myWindowNumber) {
+ // Project graphics application has a window open above ours
+ // Don't waste CPU cycles since our window is obscured by application graphics
+ newFrequency = coveredFreq;
+ msg = NULL;
+ windowIsCovered();
+ }
}
+ } else {
+ newFrequency = coveredFreq;
}
- } else {
- newFrequency = coveredFreq;
}
}
-
+
+ // Draw our moving BOINC logo and screensaver status text
+
// Clear the previous drawing area
currentDrawingRect = gMovingRect;
currentDrawingRect.origin.x = (float) ((int)gCurrentPosition.x);
@@ -464,10 +550,6 @@ int signof(float x) {
HIThemeGetTextDimensions(cf_msg, (float)gMovingRect.size.width, &textInfo, NULL, &gActualTextBoxHeight, NULL);
gActualTextBoxHeight += TEXTBOXTOPBORDER;
- // Use only APIs available in Mac OS 10.3.9
-// HIThemeSetTextFill(kThemeTextColorWhite, NULL, myContext, kHIThemeOrientationNormal);
-// SetThemeTextColor(kThemeTextColorWhite, 32, true);
-
CGFloat myWhiteComponents[] = {1.0, 1.0, 1.0, 1.0};
CGColorSpaceRef myColorSpace = CGColorSpaceCreateDeviceRGB ();
CGColorRef myTextColor = CGColorCreate(myColorSpace, myWhiteComponents);
@@ -507,6 +589,11 @@ int signof(float x) {
doBoinc_Sleep(timeToBlock);
}
}
+
+ // Check for a new graphics app sending us data
+ if (UseSharedOffscreenBuffer()) {
+ [mySharedGraphicsController testConnection];
+ }
}
- (BOOL)hasConfigureSheet {
@@ -649,3 +736,356 @@ Bad:
}
@end
+
+// On OS 10.13 or later, use MachO comunication and IOSurfaceBuffer to
+// display the graphics output of our child graphics apps in our window.
+// All code past this point is for that implementation.
+
+// Adapted from Apple Developer Tech Support Sample Code MutiGPUIOSurface:
+// <https://developer.apple.com/library/content/samplecode/MultiGPUIOSurface>
+
+#define NUM_IOSURFACE_BUFFERS 2
+
+ at interface SharedGraphicsController()
+{
+ NSMachPort *serverPort;
+ NSMachPort *localPort;
+
+ uint32_t serverPortName;
+ uint32_t localPortName;
+
+ int32_t clientIndex;
+ uint32_t nextFrameIndex;
+
+ NSView *screenSaverView;
+ saverOpenGLView *openGLView;
+
+ IOSurfaceRef _ioSurfaceBuffers[NUM_IOSURFACE_BUFFERS];
+ mach_port_t _ioSurfaceMachPorts[NUM_IOSURFACE_BUFFERS];
+ GLuint _textureNames[NUM_IOSURFACE_BUFFERS];
+}
+ at end
+
+static bool okToDraw;
+
+ at implementation SharedGraphicsController
+
+- (instancetype)init:(NSView*)saverView {
+ screenSaverView = saverView;
+
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(portDied:) name:NSPortDidBecomeInvalidNotification object:nil];
+
+ [self testConnection];
+
+ return self;
+}
+
+
+- (void) testConnection
+{
+ mach_port_t servicePortNum = MACH_PORT_NULL;
+ kern_return_t machErr;
+ char *portName = "edu.berkeley.boincsaver";
+
+ // Try to check in with master.
+// NSMachBootstrapServer is deprecated in OS 10.13, so use bootstrap_look_up
+// serverPort = [(NSMachPort *)([[NSMachBootstrapServer sharedInstance] portForName:@"edu.berkeley.boincsaver"]) retain];
+ machErr = bootstrap_look_up(bootstrap_port, portName, &servicePortNum);
+ if (machErr == KERN_SUCCESS) {
+ serverPort = (NSMachPort*)[NSMachPort portWithMachPort:servicePortNum];
+ } else {
+ serverPort = MACH_PORT_NULL;
+ }
+
+ if(serverPort != MACH_PORT_NULL)
+ {
+ // Create our own local port.
+ localPort = [[NSMachPort alloc] init];
+
+ // Retrieve raw mach port names.
+ serverPortName = [serverPort machPort];
+ localPortName = [localPort machPort];
+
+ // Register our local port with the current runloop.
+ [localPort setDelegate:self];
+ [localPort scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
+
+ // Check in with server.
+ int kr;
+ kr = _MGCCheckinClient(serverPortName, localPortName, &clientIndex);
+ if(kr != 0)
+ [NSApp terminate:nil];
+
+ openGLView = [[saverOpenGLView alloc] initWithFrame:[screenSaverView frame]];
+
+ [screenSaverView addSubview:openGLView];
+
+ runningSharedGraphics = true;
+
+ if (childPid) {
+ gfxAppStartTime = 0.0;
+ childApp = [NSRunningApplication runningApplicationWithProcessIdentifier:childPid];
+ }
+ }
+}
+
+- (void)portDied:(NSNotification *)notification
+{
+ NSPort *port = [notification object];
+ if(port == serverPort) {
+ childApp = nil;
+ gfxAppStartTime = 0.0;
+ gfxAppPath[0] = '\0';
+
+ if ([serverPort isValid]) {
+ [serverPort invalidate];
+// [serverPort release];
+ }
+ serverPort = nil;
+ [localPort removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
+
+ if ([localPort isValid]) {
+ [localPort invalidate];
+ }
+// [localPort release];
+ localPort = nil;
+
+ int i;
+ for(i = 0; i < NUM_IOSURFACE_BUFFERS; i++) {
+ if (_ioSurfaceBuffers[i]) {
+ CFRelease(_ioSurfaceBuffers[i]);
+ _ioSurfaceBuffers[i] = nil;
+ }
+
+ // if (glIsTexture(_textureNames[i])) {
+ // glDeleteTextures(1, _textureNames[i]);
+ // }
+ _textureNames[i] = 0;
+
+ if (_ioSurfaceMachPorts[i] != MACH_PORT_NULL) {
+ mach_port_deallocate(mach_task_self(), _ioSurfaceMachPorts[i]);
+ _ioSurfaceMachPorts[i] = MACH_PORT_NULL;
+ }
+ }
+
+ if ((serverPort == nil) && (localPort == nil)) {
+ runningSharedGraphics = false;
+ [openGLView removeFromSuperview]; // Releases openGLView
+ }
+ }
+}
+- (void)handleMachMessage:(void *)msg
+{
+ union __ReplyUnion___MGCMGSServer_subsystem reply;
+
+ mach_msg_header_t *reply_header = (void *)&reply;
+ kern_return_t kr;
+
+ if(MGSServer_server(msg, reply_header) && reply_header->msgh_remote_port != MACH_PORT_NULL)
+ {
+ kr = mach_msg(reply_header, MACH_SEND_MSG, reply_header->msgh_size, 0, MACH_PORT_NULL,
+ 0, MACH_PORT_NULL);
+ if(kr != 0)
+ [NSApp terminate:nil];
+ }
+}
+
+- (kern_return_t)displayFrame:(int32_t)frameIndex surfacemachport:(mach_port_t)iosurface_port
+{
+ nextFrameIndex = frameIndex;
+
+ if(!_ioSurfaceBuffers[frameIndex])
+ {
+ _ioSurfaceBuffers[frameIndex] = IOSurfaceLookupFromMachPort(iosurface_port);
+ _ioSurfaceMachPorts[frameIndex] = iosurface_port;
+ }
+ if(!_textureNames[frameIndex])
+ {
+ _textureNames[frameIndex] = [openGLView setupIOSurfaceTexture:_ioSurfaceBuffers[frameIndex]];
+ }
+
+ okToDraw = true; // Tell drawRect that we have real data to display
+
+ [openGLView setNeedsDisplay:YES];
+ [openGLView display];
+
+ return 0;
+}
+
+// For the MachO client, this is a no-op.
+kern_return_t _MGSCheckinClient(mach_port_t server_port, mach_port_t client_port,
+ int32_t *client_index)
+{
+ return 0;
+}
+
+kern_return_t _MGSDisplayFrame(mach_port_t server_port, int32_t frame_index, mach_port_t iosurface_port)
+{
+ return [mySharedGraphicsController displayFrame:frame_index surfacemachport:iosurface_port];
+}
+
+- (GLuint)currentTextureName
+{
+ return _textureNames[nextFrameIndex];
+}
+
+ at end
+
+ at implementation saverOpenGLView
+
+- (instancetype)initWithFrame:(NSRect)frame {
+ NSOpenGLPixelFormatAttribute attribs [] =
+ {
+// NSOpenGLPFAWindow,
+ NSOpenGLPFADoubleBuffer,
+ NSOpenGLPFAAccelerated,
+ NSOpenGLPFANoRecovery,
+ NSOpenGLPFAColorSize, (NSOpenGLPixelFormatAttribute)32,
+ NSOpenGLPFAAlphaSize, (NSOpenGLPixelFormatAttribute)8,
+ NSOpenGLPFADepthSize, (NSOpenGLPixelFormatAttribute)24,
+ (NSOpenGLPixelFormatAttribute) 0
+ };
+
+ NSOpenGLPixelFormat *pix_fmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
+
+ if(!pix_fmt)
+ [ NSApp terminate:nil];
+
+ self = [super initWithFrame:frame pixelFormat:pix_fmt];
+
+
+ [[self openGLContext] makeCurrentContext];
+
+ // drawRect is apparently called due to the above code, causing the
+ // screen to flash unless we prevent any actual drawing, so tell
+ // drawRect that we do not yet have real data to display
+ okToDraw = false;
+
+ return self;
+}
+
+- (void)prepareOpenGL
+{
+ [super prepareOpenGL];
+}
+
+- (void)update
+{
+ // Override to do nothing.
+}
+
+// Create an IOSurface backed texture
+- (GLuint)setupIOSurfaceTexture:(IOSurfaceRef)ioSurfaceBuffer
+{
+ GLuint name;
+ CGLContextObj cgl_ctx = (CGLContextObj)[[self openGLContext] CGLContextObj];
+
+ glGenTextures(1, &name);
+
+ glBindTexture(GL_TEXTURE_RECTANGLE, name);
+ // At the moment, CGLTexImageIOSurface2D requires the GL_TEXTURE_RECTANGLE target
+ CGLTexImageIOSurface2D(cgl_ctx, GL_TEXTURE_RECTANGLE, GL_RGBA, (GLsizei)self.bounds.size.width, (GLsizei)self.bounds.size.height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
+ ioSurfaceBuffer, 0);
+
+ glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ return name;
+}
+
+- (BOOL)isOpaque
+{
+ return YES;
+}
+
+// Render a quad with the the IOSurface backed texture
+- (void)renderTextureFromIOSurfaceWithWidth:(GLsizei)logoWidth height:(GLsizei)logoHeight
+{
+ GLfloat quad[] = {
+ //x, y s, t
+ (GLfloat)logoWidth, 0.0f, 0.0f, 0.0f,
+ 0.0f, (GLfloat)logoHeight, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f
+ };
+
+ GLint saveMatrixMode;
+
+ glGetIntegerv(GL_MATRIX_MODE, &saveMatrixMode);
+ glMatrixMode(GL_TEXTURE);
+ glPushMatrix();
+ glLoadMatrixf(quad);
+ glMatrixMode(saveMatrixMode);
+
+ glBindTexture(GL_TEXTURE_RECTANGLE, [mySharedGraphicsController currentTextureName]);
+ glEnable(GL_TEXTURE_RECTANGLE);
+
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+
+ //Draw textured quad
+ glBegin(GL_QUADS);
+ glTexCoord2f(0.0, 0.0);
+ glVertex3f(-1.0, -1.0, 0.0);
+ glTexCoord2f(1.0, 0.0);
+ glVertex3f(1.0, -1.0, 0.0);
+ glTexCoord2f(1.0, 1.0);
+ glVertex3f(1.0, 1.0, 0.0);
+ glTexCoord2f(0.0, 1.0);
+ glVertex3f(-1.0, 1.0, 0.0);
+ glEnd();
+
+ glDisable(GL_TEXTURE_RECTANGLE);
+
+ glGetIntegerv(GL_MATRIX_MODE, &saveMatrixMode);
+ glMatrixMode(GL_TEXTURE);
+ glPopMatrix();
+ glMatrixMode(saveMatrixMode);
+
+}
+
+- (void)drawRect:(NSRect)theRect
+{
+ glViewport(0, 0, (GLint)theRect.size.width, (GLint)theRect.size.height);
+
+ glClearColor(0.0, 0.0, 0.0, 0.0);
+
+ glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
+
+ // drawRect is apparently called before we have real data to display,
+ // causing the screen to flash unless we prevent any actual drawing.
+ if (!okToDraw) {
+ [[self openGLContext] flushBuffer];
+ return;
+}
+
+ // MachO client draws with current IO surface contents as texture
+ [self renderTextureFromIOSurfaceWithWidth:(GLsizei)self.bounds.size.width height:(GLsizei)self.bounds.size.height];
+
+ [[self openGLContext] flushBuffer];
+}
+
+ at end
+
+
+// On OS 10.13 or later, use MachO comunication and IOSurfaceBuffer to
+// display the graphics output of our child graphics apps in our window.
+static bool UseSharedOffscreenBuffer() {
+ static bool alreadyTested = false;
+ static bool needSharedGfxBuffer = false;
+
+//return true; // FOR TESTING ONLY
+ if (alreadyTested) {
+ return needSharedGfxBuffer;
+ }
+ alreadyTested = true;
+ if (compareOSVersionTo(10, 13) >= 0) {
+ needSharedGfxBuffer = true;
+ return true;
+ }
+ return false;
+}
+
+
diff --git a/clientscr/mac_saver_module.cpp b/clientscr/mac_saver_module.cpp
index ff6dba9..8c67cdb 100644
--- a/clientscr/mac_saver_module.cpp
+++ b/clientscr/mac_saver_module.cpp
@@ -1,6 +1,6 @@
// This file is part of BOINC.
// http://boinc.berkeley.edu
-// Copyright (C) 2008 University of California
+// Copyright (C) 2017 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
@@ -106,6 +106,7 @@ const char * CantLaunchDefaultGFXAppMsg = "Can't launch default screensaver mod
const char * DefaultGFXAppCantRPCMsg = "Default screensaver module couldn't connect to BOINC application";
const char * DefaultGFXAppCrashedMsg = "Default screensaver module had an unrecoverable error";
const char * RunningOnBatteryMsg = "Computing and screensaver disabled while running on battery power.";
+const char * IncompatibleMsg = " is not compatible with this version of OS X.";
//const char * BOINCExitedSaverMode = "BOINC is no longer in screensaver mode.";
@@ -173,6 +174,62 @@ void closeBOINCSaver() {
}
+void incompatibleGfxApp(char * appPath, pid_t pid, int slot){
+ char *p;
+ static char buf[1024];
+ static double msgstartTime = 0.0;
+ int retval;
+ bool gotAppName = false;
+ int exitStatus;
+
+ if (gspScreensaver) {
+ if (msgstartTime == 0.0) {
+ msgstartTime = getDTime();
+ buf[0] = '\0';
+
+ if (gspScreensaver->HasProcessExited(pid, exitStatus)) {
+ return;
+ }
+
+ retval = gspScreensaver->rpc->get_state(gspScreensaver->state);
+ if (!retval) {
+ strlcpy(buf, "Screensaver ", sizeof(buf));
+ for (int i=0; i<gspScreensaver->state.results.size(); i++) {
+ RESULT* r = gspScreensaver->state.results[i];
+ if (r->slot == slot) {
+ if (r->app) {
+ if (r->app->user_friendly_name[0]) {
+ strlcat(buf, "of application ", sizeof(buf));
+ strlcat(buf, r->app->user_friendly_name, sizeof(buf));
+ gotAppName = true;
+ }
+ }
+ }
+ }
+ } // if (!retval)
+
+ if (!gotAppName) {
+ p = strrchr(appPath, '/');
+ if (!p) p = appPath;
+ strlcat(buf, "\"", sizeof(buf));
+ strlcat(buf, p+1, sizeof(buf));
+ strlcat(buf, "\"", sizeof(buf));
+ }
+ strlcat(buf, IncompatibleMsg, sizeof(buf));
+ gspScreensaver->setSSMessageText(buf);
+ gspScreensaver->SetError(0, SCRAPPERR_GFXAPPINCOMPATIBLE);
+ } // End if (msgstartTime == 0.0)
+
+ if (msgstartTime && (getDTime() - msgstartTime > 5.0)) {
+ gspScreensaver->markAsIncompatible(appPath);
+ launchedGfxApp("", 0, -1);
+ msgstartTime = 0.0;
+ gspScreensaver->terminate_screensaver(pid, NULL);
+ }
+ }
+}
+
+
double getGFXDefaultPeriod() {
if (gspScreensaver) {
return gspScreensaver->m_fGFXDefaultPeriod;
@@ -536,6 +593,9 @@ int CScreensaver::getSSMessage(char **theMessage, int* coveredFreq) {
case SCRAPPERR_DEFAULTGFXAPPCRASHED:
setSSMessageText(DefaultGFXAppCrashedMsg);
break;
+ case SCRAPPERR_GFXAPPINCOMPATIBLE:
+ // Message was set in incompatibleGfxApp()
+ break;
default:
// m_bErrorMode is TRUE if we should display moving logo (no graphics app is running)
// m_bErrorMode is FALSE if a graphics app was launched and has not exit
diff --git a/clientscr/screensaver.cpp b/clientscr/screensaver.cpp
index 657e570..0e4b5c7 100644
--- a/clientscr/screensaver.cpp
+++ b/clientscr/screensaver.cpp
@@ -1,6 +1,6 @@
// This file is part of BOINC.
// http://boinc.berkeley.edu
-// Copyright (C) 2008 University of California
+// Copyright (C) 2017 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
@@ -28,6 +28,8 @@
#ifdef __APPLE__
#include <Carbon/Carbon.h>
#include <sys/wait.h>
+#include <app_ipc.h>
+#include <malloc/malloc.h>
#endif
// Common application includes
@@ -83,22 +85,35 @@ bool CScreensaver::is_same_task(RESULT* taska, RESULT* taskb) {
}
int CScreensaver::count_active_graphic_apps(RESULTS& res, RESULT* exclude) {
- unsigned int i = 0;
+ int i = 0;
unsigned int graphics_app_count = 0;
// Count the number of active graphics-capable apps excluding the specified result.
// If exclude is NULL, don't exclude any results.
//
- for (i = 0; i < res.results.size(); i++) {
- BOINCTRACE(_T("get_random_graphics_app -- active task detected\n"));
+ for (i = res.results.size()-1; i >=0 ; i--) {
+ BOINCTRACE(_T("count_active_graphic_apps -- active task detected\n"));
BOINCTRACE(
- _T("get_random_graphics_app -- name = '%s', path = '%s'\n"),
+ _T("count_active_graphic_apps -- name = '%s', path = '%s'\n"),
res.results[i]->name, res.results[i]->graphics_exec_path
);
if (!strlen(res.results[i]->graphics_exec_path)) continue;
if (is_same_task(res.results[i], exclude)) continue;
- BOINCTRACE(_T("get_random_graphics_app -- active task detected w/graphics\n"));
+#ifdef __APPLE__
+ // Remove it from the vector if incompatible with current version of OS X
+ if (isIncompatible(res.results[i]->graphics_exec_path)) {
+ BOINCTRACE(
+ _T("count_active_graphic_apps -- removing incompatible name = '%s', path = '%s'\n"),
+ res.results[i]->name, res.results[i]->graphics_exec_path
+ );
+ RESULT *rp = res.results[i];
+ res.results.erase(res.results.begin()+i);
+ delete rp;
+ continue;
+ }
+#endif
+ BOINCTRACE(_T("count_active_graphic_apps -- active task detected w/graphics\n"));
graphics_app_count++;
}
@@ -161,10 +176,38 @@ CLEANUP:
}
+#ifdef __APPLE__
+void CScreensaver::markAsIncompatible(char *gfxAppPath) {
+ char *buf = (char *)malloc(strlen(gfxAppPath)+1);
+ if (buf) {
+ strlcpy(buf, gfxAppPath, malloc_size(buf));
+ m_vIncompatibleGfxApps.push_back(buf);
+ BOINCTRACE(_T("markAsIncompatible -- path = '%s'\n"), gfxAppPath);
+ }
+}
+
+bool CScreensaver::isIncompatible(char *appPath) {
+ unsigned int i = 0;
+ for (i = 0; i < m_vIncompatibleGfxApps.size(); i++) {
+ BOINCTRACE(
+ _T("isIncompatible -- comparing incompatible path '%s' to candidate path %s\n"),
+ m_vIncompatibleGfxApps[i], appPath
+ );
+ if (strcmp(m_vIncompatibleGfxApps[i], appPath) == 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
+#endif
+
+
// Launch a project (science) graphics application
//
int CScreensaver::launch_screensaver(RESULT* rp, GFXAPP_ID& graphics_application) {
int retval = 0;
+
if (strlen(rp->graphics_exec_path)) {
// V6 Graphics
#ifdef __APPLE__
@@ -191,6 +234,10 @@ int CScreensaver::launch_screensaver(RESULT* rp, GFXAPP_ID& graphics_application
0,
graphics_application
);
+
+ if (graphics_application) {
+ launchedGfxApp(rp->graphics_exec_path, graphics_application, rp->slot);
+ }
#else
char* argv[3];
argv[0] = "app_graphics"; // not used
@@ -245,6 +292,10 @@ int CScreensaver::terminate_v6_screensaver(GFXAPP_ID& graphics_application) {
thePID
);
+ if (graphics_application) {
+ launchedGfxApp("", 0, -1);
+ }
+
for (i=0; i<200; i++) {
boinc_sleep(0.01); // Wait 2 seconds max
// Prevent gfx_switcher from becoming a zombie
@@ -322,6 +373,10 @@ int CScreensaver::launch_default_screensaver(char *dir_path, GFXAPP_ID& graphics
graphics_application
);
+ if (graphics_application) {
+ launchedGfxApp("boincscr", graphics_application, -1);
+ }
+
BOINCTRACE(_T("launch_default_screensaver returned %d\n"), retval);
#else
@@ -427,6 +482,7 @@ DataMgmtProcType CScreensaver::DataManagementProc() {
m_bShow_default_ss_first = false;
#ifdef __APPLE__
+ m_vIncompatibleGfxApps.clear();
default_ss_dir_path = "/Library/Application Support/BOINC Data";
#else
default_ss_dir_path = (char*)m_strBOINCInstallDirectory.c_str();
diff --git a/clientscr/screensaver.h b/clientscr/screensaver.h
index 1e27b9c..5e8a8e4 100644
--- a/clientscr/screensaver.h
+++ b/clientscr/screensaver.h
@@ -1,6 +1,6 @@
// This file is part of BOINC.
// http://boinc.berkeley.edu
-// Copyright (C) 2008 University of California
+// Copyright (C) 2017 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
@@ -57,6 +57,7 @@ enum SS_PHASE {
#define SCRAPPERR_CANTLAUNCHDEFAULTGFXAPP 0x82000014
#define SCRAPPERR_DEFAULTGFXAPPCANTCONNECT 0x82000015
#define SCRAPPERR_DEFAULTGFXAPPCRASHED 0x82000016
+#define SCRAPPERR_GFXAPPINCOMPATIBLE 0x82000017
#endif
diff --git a/configure.ac b/configure.ac
index 0faba6c..9bd7cd4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -6,7 +6,7 @@ dnl not sure exactly what the minimum version is (but 2.13 wont work)
AC_PREREQ(2.58)
dnl Set the BOINC version here. You can also use the set-version script.
-AC_INIT(BOINC, 7.8.2)
+AC_INIT(BOINC, 7.8.3)
AC_CONFIG_MACRO_DIR([m4])
LIBBOINC_VERSION=`echo ${PACKAGE_VERSION} | sed 's/\./:/g'`
AC_SUBST([LIBBOINC_VERSION])
diff --git a/lib/cc_config.cpp b/lib/cc_config.cpp
index 5add778..8aa9632 100644
--- a/lib/cc_config.cpp
+++ b/lib/cc_config.cpp
@@ -393,7 +393,7 @@ int CC_CONFIG::parse_options(XML_PARSER& xp) {
ignore_gpu_instance[PROC_TYPE_AMD_GPU].push_back(n);
continue;
}
- if (xp.parse_int("ignore_intel_gpu_dev", n)) {
+ if (xp.parse_int("ignore_intel_dev", n)) {
ignore_gpu_instance[PROC_TYPE_INTEL_GPU].push_back(n);
continue;
}
@@ -619,7 +619,7 @@ int CC_CONFIG::write(MIOFILE& out, LOG_FLAGS& log_flags) {
for (i=0; i<ignore_gpu_instance[PROC_TYPE_INTEL_GPU].size(); ++i) {
out.printf(
- " <ignore_intel_gpu_dev>%d</ignore_intel_gpu_dev>\n",
+ " <ignore_intel_dev>%d</ignore_intel_dev>\n",
ignore_gpu_instance[PROC_TYPE_INTEL_GPU][i]
);
}
diff --git a/lib/filesys.cpp b/lib/filesys.cpp
index 53c11c8..30fd5b8 100644
--- a/lib/filesys.cpp
+++ b/lib/filesys.cpp
@@ -547,9 +547,7 @@ int boinc_file_exists(const char* path) {
#ifdef _WIN32
// don't use _stat64 because it doesn't work with VS2015, XP client
DWORD dwAttrib = GetFileAttributesA(path);
- return (dwAttrib != INVALID_FILE_ATTRIBUTES
- && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)
- );
+ return dwAttrib != INVALID_FILE_ATTRIBUTES;
#else
struct stat buf;
if (stat(path, &buf)) {
diff --git a/locale/fr/BOINC-Manager.mo b/locale/fr/BOINC-Manager.mo
index ef44b8a..bb67ff8 100644
Binary files a/locale/fr/BOINC-Manager.mo and b/locale/fr/BOINC-Manager.mo differ
diff --git a/version.log b/version.log
index 194172b..bb9f54c 100644
--- a/version.log
+++ b/version.log
@@ -1 +1 @@
-7.8.2
+7.8.3
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-boinc/boinc.git
More information about the pkg-boinc-commits
mailing list