Fix shutdown codepaths

- Ensures various shutdown codepaths (interface, cpu/audio, main/video, ...) run on proper thread(s)
    - Actually now runs the CloseAL() code
    - Try to ensure all detached threads exit ... seems to help keep Valgrind happy =)
This commit is contained in:
Aaron Culliney 2015-05-31 12:59:26 -07:00
parent a796a9f14c
commit 80b880550f
7 changed files with 108 additions and 18 deletions

View File

@ -1270,7 +1270,6 @@ void c_interface_parameters()
if (ch == 'Y') if (ch == 'Y')
{ {
save_settings(); save_settings();
c_eject_6( 0 ); c_eject_6( 0 );
c_interface_print_screen( screen ); c_interface_print_screen( screen );
c_eject_6( 1 ); c_eject_6( 1 );
@ -1278,13 +1277,9 @@ void c_interface_parameters()
#ifdef __linux__ #ifdef __linux__
LOG("Back to Linux, w00t!\n"); LOG("Back to Linux, w00t!\n");
#endif #endif
#ifdef AUDIO_ENABLED
speaker_destroy();
MB_Destroy();
#endif
video_shutdown(); video_shutdown();
exit( 0 ); c_interface_exit(ch);
return;
} }
} }

View File

@ -444,13 +444,14 @@ int c_mygetch(int block)
{ {
int retval; int retval;
if (block) if (emulator_shutting_down) {
next_key = kESC;
}
while (next_key == -1 && block)
{ {
while (next_key == -1) static struct timespec ts = { .tv_sec=0, .tv_nsec=33333333 };
{ nanosleep(&ts, NULL); // 30Hz framerate
static struct timespec ts = { .tv_sec=0, .tv_nsec=33333333 };
nanosleep(&ts, NULL); // 30Hz framerate
}
} }
retval = next_key; retval = next_key;

View File

@ -22,6 +22,7 @@
extern uint8_t apple_iie_rom[32768]; extern uint8_t apple_iie_rom[32768];
bool emulator_shutting_down = false;
bool do_logging = true; // also controlled by NDEBUG bool do_logging = true; // also controlled by NDEBUG
FILE *error_log = NULL; FILE *error_log = NULL;
@ -604,6 +605,44 @@ void c_initialize_firsttime(void) {
#if !TESTING && !defined(__APPLE__) && !defined(ANDROID) #if !TESTING && !defined(__APPLE__) && !defined(ANDROID)
extern void *cpu_thread(void *dummyptr); extern void *cpu_thread(void *dummyptr);
static void _shutdown_threads(void) {
LOG("Emulator waiting for other threads to clean up...");
#if !__linux__
#warning FIXME TODO ideally we have a more deterministic thread waiting routine ...
sleep(2); // =P
#else
do {
DIR *dir = opendir("/proc/self/task");
if (!dir) {
ERRLOG("Cannot open /proc/self/task !");
break;
}
int thread_count = 0;
struct dirent *d = NULL;
while ((d = readdir(dir)) != NULL) {
if (strncmp(".", d->d_name, 2) == 0) {
// ignore
} else if (strncmp("..", d->d_name, 3) == 0) {
// ignore
} else {
++thread_count;
}
}
closedir(dir);
assert(thread_count >= 1 && "there must at least be one thread =P");
if (thread_count == 1) {
break;
}
static struct timespec ts = { .tv_sec=0, .tv_nsec=33333333 };
nanosleep(&ts, NULL); // 30Hz framerate
} while (1);
#endif
}
int main(int _argc, char **_argv) { int main(int _argc, char **_argv) {
argc = _argc; argc = _argc;
argv = _argv; argv = _argv;
@ -618,6 +657,17 @@ int main(int _argc, char **_argv) {
pthread_create(&cpu_thread_id, NULL, (void *)&cpu_thread, (void *)NULL); pthread_create(&cpu_thread_id, NULL, (void *)&cpu_thread, (void *)NULL);
video_main_loop(); video_main_loop();
assert(emulator_shutting_down && "emulator is properly shutting down");
LOG("Emulator waiting for CPU thread clean up...");
if (pthread_join(cpu_thread_id, NULL)) {
ERRLOG("OOPS: pthread_join of CPU thread ...");
}
_shutdown_threads();
return 0;
} }
#endif #endif

View File

@ -98,6 +98,8 @@ extern uint32_t softswitches;
misc.c functions misc.c functions
------------------------------------------------------------------------- */ ------------------------------------------------------------------------- */
extern bool emulator_shutting_down;
void c_initialize_firsttime(); void c_initialize_firsttime();
void c_initialize_sound_hooks(); void c_initialize_sound_hooks();
void c_disable_sound_hooks(); void c_disable_sound_hooks();

View File

@ -390,11 +390,29 @@ void *cpu_thread(void *dummyptr) {
} }
} }
} }
} while (!emul_reinitialize);
if (UNLIKELY(emul_reinitialize)) {
break;
}
if (UNLIKELY(emulator_shutting_down)) {
break;
}
} while (1);
if (UNLIKELY(emulator_shutting_down)) {
break;
}
reinitialize(); reinitialize();
} while (1); } while (1);
#ifdef AUDIO_ENABLED
speaker_destroy();
MB_Destroy();
DSUninit();
#endif
return NULL; return NULL;
} }

View File

@ -619,11 +619,9 @@ static void gldriver_init_common(void) {
} }
} }
static void gldriver_shutdown(void) { static void _gldriver_shutdown(void) {
#if USE_GLUT
glutDestroyWindow(glutWindow);
#endif
// Cleanup all OpenGL objects // Cleanup all OpenGL objects
emulator_shutting_down = true;
glDeleteTextures(1, &a2TextureName); glDeleteTextures(1, &a2TextureName);
a2TextureName = UNINITIALIZED_GL; a2TextureName = UNINITIALIZED_GL;
_destroy_VAO(crtVAOName); _destroy_VAO(crtVAOName);
@ -632,6 +630,15 @@ static void gldriver_shutdown(void) {
glDeleteProgram(program); glDeleteProgram(program);
program = UNINITIALIZED_GL; program = UNINITIALIZED_GL;
glnode_shutdownNodes(); glnode_shutdownNodes();
LOG("Completed GLDriver shutdown ...");
}
static void gldriver_shutdown(void) {
#if USE_GLUT
glutLeaveMainLoop();
#else
_gldriver_shutdown();
#endif
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -876,7 +883,10 @@ static void gldriver_init(void *fbo) {
static void gldriver_main_loop(void) { static void gldriver_main_loop(void) {
#if USE_GLUT #if USE_GLUT
glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_GLUTMAINLOOP_RETURNS);
glutMainLoop(); glutMainLoop();
LOG("GLUT main loop finished...");
_gldriver_shutdown();
#endif #endif
// fall through if not GLUT // fall through if not GLUT
} }

14
valgrind.suppress Normal file
View File

@ -0,0 +1,14 @@
{
IGNORE glutCreateWindow allocation
Memcheck:Leak
match-leak-kinds: definite
fun:malloc
obj:/usr/lib/x86_64-linux-gnu/dri/i965_dri.so
obj:/usr/lib/x86_64-linux-gnu/libGL.so.1.2.0
obj:/usr/lib/x86_64-linux-gnu/libGL.so.1.2.0
obj:/usr/lib/x86_64-linux-gnu/libGL.so.1.2.0
fun:glXMakeContextCurrent
fun:fgOpenWindow
fun:fgCreateWindow
fun:glutCreateWindow
}