mirror of https://github.com/BOINC/boinc.git
API: my revisions to David Kim's Android version
This commit is contained in:
parent
35d40bbfc0
commit
d726d1b0bc
|
@ -21,14 +21,31 @@
|
||||||
// 1) Thread structure:
|
// 1) Thread structure:
|
||||||
// Sequential apps
|
// Sequential apps
|
||||||
// Unix
|
// Unix
|
||||||
// getting CPU time and suspend/resume have to be done
|
// Suspend/resume have to be done in the worker thread,
|
||||||
// in the worker thread, so we use a SIGALRM signal handler.
|
// so we use a 10 Hz SIGALRM signal handler.
|
||||||
// However, many library functions and system calls
|
// Also get CPU time (getrusage()) in the signal handler.
|
||||||
|
// Note: many library functions and system calls
|
||||||
// are not "asynch signal safe": see, e.g.
|
// are not "asynch signal safe": see, e.g.
|
||||||
// http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html#tag_02_04_03
|
// http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html#tag_02_04_03
|
||||||
// (e.g. sprintf() in a signal handler hangs Mac OS X)
|
// (e.g. sprintf() in a signal handler hangs Mac OS X).
|
||||||
// so we do as little as possible in the signal handler,
|
// Can't do floating-point math because FP regs not saved.
|
||||||
|
// So we do as little as possible in the signal handler,
|
||||||
// and do the rest in a separate "timer thread".
|
// and do the rest in a separate "timer thread".
|
||||||
|
// - send status and graphics messages to client
|
||||||
|
// - handle messages from client
|
||||||
|
// - set ready-to-checkpoint flag
|
||||||
|
// - check heartbeat
|
||||||
|
// - call app-defined timer callback function
|
||||||
|
// Mac: similar to Linux,
|
||||||
|
// but getrusage() in the worker signal handler causes crashes,
|
||||||
|
// so do it in the timer thread (GETRUSAGE_IN_TIMER_THREAD)
|
||||||
|
// TODO: why not do this on Linux too?
|
||||||
|
// Android: similar to Linux,
|
||||||
|
// but setitimer() causes crashes on some Android versions,
|
||||||
|
// so instead of using a periodic signal,
|
||||||
|
// have the timer thread send SIGALRM signals to the worker thread
|
||||||
|
// every .1 sec.
|
||||||
|
// TODO: for uniformity should we do this on Linux as well?
|
||||||
// Win
|
// Win
|
||||||
// the timer thread does everything
|
// the timer thread does everything
|
||||||
// Multi-thread apps:
|
// Multi-thread apps:
|
||||||
|
@ -109,9 +126,12 @@
|
||||||
using std::vector;
|
using std::vector;
|
||||||
|
|
||||||
//#define DEBUG_BOINC_API
|
//#define DEBUG_BOINC_API
|
||||||
|
// enable a bunch of fprintfs to stderr
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
#include "mac_backtrace.h"
|
#include "mac_backtrace.h"
|
||||||
|
#endif
|
||||||
|
#if defined(__APPLE__) || defined(ANDROID)
|
||||||
#define GETRUSAGE_IN_TIMER_THREAD
|
#define GETRUSAGE_IN_TIMER_THREAD
|
||||||
// call getrusage() in the timer thread,
|
// call getrusage() in the timer thread,
|
||||||
// rather than in the worker thread's signal handler
|
// rather than in the worker thread's signal handler
|
||||||
|
@ -284,7 +304,7 @@ static int setup_shared_mem() {
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if (aid.shmem_seg_name == -1) {
|
if (aid.shmem_seg_name == -1) {
|
||||||
// Version 6 Unix/Linux/Mac client
|
// Version 6 Unix/Linux/Mac client
|
||||||
if (attach_shmem_mmap(MMAPPED_FILE_NAME, (void**)&app_client_shm->shm)) {
|
if (attach_shmem_mmap(MMAPPED_FILE_NAME, (void**)&app_client_shm->shm)) {
|
||||||
delete app_client_shm;
|
delete app_client_shm;
|
||||||
app_client_shm = NULL;
|
app_client_shm = NULL;
|
||||||
|
@ -686,8 +706,8 @@ static void send_trickle_up_msg() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: a non-zero status tells the client that we're exiting with
|
// NOTE: a non-zero status tells the client that we're exiting with
|
||||||
// an "unrecoverable error", which will be reported back to server.
|
// an "unrecoverable error", which will be reported back to server.
|
||||||
// A zero exit-status tells the client we've successfully finished the result.
|
// A zero exit-status tells the client we've successfully finished the result.
|
||||||
//
|
//
|
||||||
int boinc_finish_message(int status, const char* msg, bool is_notice) {
|
int boinc_finish_message(int status, const char* msg, bool is_notice) {
|
||||||
|
@ -810,6 +830,9 @@ int boinc_is_standalone() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// called from the timer thread if we need to exit,
|
||||||
|
// e.g. quit message from client, or client has gone away
|
||||||
|
//
|
||||||
static void exit_from_timer_thread(int status) {
|
static void exit_from_timer_thread(int status) {
|
||||||
#ifdef DEBUG_BOINC_API
|
#ifdef DEBUG_BOINC_API
|
||||||
char buf[256];
|
char buf[256];
|
||||||
|
@ -826,11 +849,22 @@ static void exit_from_timer_thread(int status) {
|
||||||
//
|
//
|
||||||
boinc_exit(status);
|
boinc_exit(status);
|
||||||
#else
|
#else
|
||||||
// but on Unix there are synchronization problems;
|
// but on Unix there are synchronization problems if we exit here;
|
||||||
// set a flag telling the worker thread to exit
|
// set a flag telling the worker thread to exit
|
||||||
//
|
//
|
||||||
worker_thread_exit_status = status;
|
worker_thread_exit_status = status;
|
||||||
worker_thread_exit_flag = true;
|
worker_thread_exit_flag = true;
|
||||||
|
#ifdef ANDROID
|
||||||
|
// trigger the worker signal handler, which will call boinc_exit()
|
||||||
|
//
|
||||||
|
pthread_kill(worker_thread_handle, SIGALRM);
|
||||||
|
|
||||||
|
// the exit should happen more or less instantly.
|
||||||
|
// But if we're still here after 1 sec, exit directly
|
||||||
|
//
|
||||||
|
sleep(1.0);
|
||||||
|
boinc_exit(status);
|
||||||
|
#endif
|
||||||
pthread_exit(NULL);
|
pthread_exit(NULL);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -1093,6 +1127,9 @@ static void handle_process_control_msg() {
|
||||||
BOINCINFO("Received quit message");
|
BOINCINFO("Received quit message");
|
||||||
boinc_status.quit_request = true;
|
boinc_status.quit_request = true;
|
||||||
if (!in_critical_section && options.direct_process_action) {
|
if (!in_critical_section && options.direct_process_action) {
|
||||||
|
release_mutex();
|
||||||
|
// we hold mutex, and it's possible that worker
|
||||||
|
// is waiting on it, so release it
|
||||||
exit_from_timer_thread(0);
|
exit_from_timer_thread(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1121,7 +1158,7 @@ static void handle_process_control_msg() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// timer handler; runs in the timer thread
|
// timer handler; called every 0.1 sec in the timer thread
|
||||||
//
|
//
|
||||||
static void timer_handler() {
|
static void timer_handler() {
|
||||||
char buf[512];
|
char buf[512];
|
||||||
|
@ -1162,6 +1199,11 @@ static void timer_handler() {
|
||||||
handle_process_control_msg();
|
handle_process_control_msg();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#ifdef ANDROID
|
||||||
|
// Trigger call to worker_signal_handler() in the worker thread
|
||||||
|
//
|
||||||
|
pthread_kill(worker_thread_handle, SIGALRM);
|
||||||
|
#endif
|
||||||
if (interrupt_count % TIMERS_PER_SEC) return;
|
if (interrupt_count % TIMERS_PER_SEC) return;
|
||||||
|
|
||||||
#ifdef DEBUG_BOINC_API
|
#ifdef DEBUG_BOINC_API
|
||||||
|
@ -1201,7 +1243,7 @@ static void timer_handler() {
|
||||||
last_wu_cpu_time = cur_cpu + initial_wu_cpu_time;
|
last_wu_cpu_time = cur_cpu + initial_wu_cpu_time;
|
||||||
update_app_progress(last_wu_cpu_time, last_checkpoint_cpu_time);
|
update_app_progress(last_wu_cpu_time, last_checkpoint_cpu_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (have_new_trickle_up || have_new_upload_file) {
|
if (have_new_trickle_up || have_new_upload_file) {
|
||||||
send_trickle_up_msg();
|
send_trickle_up_msg();
|
||||||
}
|
}
|
||||||
|
@ -1232,7 +1274,6 @@ static void timer_handler() {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|
||||||
DWORD WINAPI timer_thread(void *) {
|
DWORD WINAPI timer_thread(void *) {
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
Sleep((int)(TIMER_PERIOD*1000));
|
Sleep((int)(TIMER_PERIOD*1000));
|
||||||
timer_handler();
|
timer_handler();
|
||||||
|
@ -1270,17 +1311,6 @@ static void worker_signal_handler(int) {
|
||||||
}
|
}
|
||||||
if (options.direct_process_action) {
|
if (options.direct_process_action) {
|
||||||
while (boinc_status.suspended && in_critical_section==0) {
|
while (boinc_status.suspended && in_critical_section==0) {
|
||||||
#ifdef ANDROID
|
|
||||||
// per-thread signal masking doesn't work
|
|
||||||
// on old (pre-4.1) versions of Android.
|
|
||||||
// If we're handling this signal in the timer thread,
|
|
||||||
// send signal explicitly to worker thread.
|
|
||||||
//
|
|
||||||
if (pthread_self() == timer_thread_handle) {
|
|
||||||
pthread_kill(worker_thread_handle, SIGALRM);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
sleep(1); // don't use boinc_sleep() because it does FP math
|
sleep(1); // don't use boinc_sleep() because it does FP math
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1317,7 +1347,7 @@ int start_timer_thread() {
|
||||||
);
|
);
|
||||||
return errno;
|
return errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!options.normal_thread_priority) {
|
if (!options.normal_thread_priority) {
|
||||||
// lower our (worker thread) priority
|
// lower our (worker thread) priority
|
||||||
//
|
//
|
||||||
|
@ -1341,28 +1371,35 @@ int start_timer_thread() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
// set up a periodic SIGALRM, to be handled by the worker thread
|
|
||||||
|
// called in the worker thread.
|
||||||
|
// set up a handler for SIGALRM.
|
||||||
|
// If Android, we'll get signals from the time thread.
|
||||||
|
// otherwise, set an interval timer to deliver signals
|
||||||
//
|
//
|
||||||
static int start_worker_signals() {
|
static int start_worker_signals() {
|
||||||
int retval;
|
int retval;
|
||||||
struct sigaction sa;
|
struct sigaction sa;
|
||||||
itimerval value;
|
memset(&sa, 0, sizeof(sa));
|
||||||
sa.sa_handler = worker_signal_handler;
|
sa.sa_handler = worker_signal_handler;
|
||||||
sa.sa_flags = SA_RESTART;
|
sa.sa_flags = SA_RESTART;
|
||||||
sigemptyset(&sa.sa_mask);
|
sigemptyset(&sa.sa_mask);
|
||||||
retval = sigaction(SIGALRM, &sa, NULL);
|
retval = sigaction(SIGALRM, &sa, NULL);
|
||||||
if (retval) {
|
if (retval) {
|
||||||
perror("boinc start_timer_thread() sigaction");
|
perror("boinc start_worker_signals(): sigaction failed");
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
#ifndef ANDROID
|
||||||
|
itimerval value;
|
||||||
value.it_value.tv_sec = 0;
|
value.it_value.tv_sec = 0;
|
||||||
value.it_value.tv_usec = (int)(TIMER_PERIOD*1e6);
|
value.it_value.tv_usec = (int)(TIMER_PERIOD*1e6);
|
||||||
value.it_interval = value.it_value;
|
value.it_interval = value.it_value;
|
||||||
retval = setitimer(ITIMER_REAL, &value, NULL);
|
retval = setitimer(ITIMER_REAL, &value, NULL);
|
||||||
if (retval) {
|
if (retval) {
|
||||||
perror("boinc start_timer_thread() setitimer");
|
perror("boinc start_worker_thread(): setitimer failed");
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue