diff --git a/src/interface.c b/src/interface.c index 33e0a7c5..fca50cba 100644 --- a/src/interface.c +++ b/src/interface.c @@ -1270,7 +1270,6 @@ void c_interface_parameters() if (ch == 'Y') { save_settings(); - c_eject_6( 0 ); c_interface_print_screen( screen ); c_eject_6( 1 ); @@ -1278,13 +1277,9 @@ void c_interface_parameters() #ifdef __linux__ LOG("Back to Linux, w00t!\n"); #endif -#ifdef AUDIO_ENABLED - speaker_destroy(); - MB_Destroy(); -#endif - video_shutdown(); - exit( 0 ); + c_interface_exit(ch); + return; } } diff --git a/src/keys.c b/src/keys.c index 22667ed1..a19696b1 100644 --- a/src/keys.c +++ b/src/keys.c @@ -444,13 +444,14 @@ int c_mygetch(int block) { 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; diff --git a/src/misc.c b/src/misc.c index 359a1260..d7c90319 100644 --- a/src/misc.c +++ b/src/misc.c @@ -22,6 +22,7 @@ extern uint8_t apple_iie_rom[32768]; +bool emulator_shutting_down = false; bool do_logging = true; // also controlled by NDEBUG FILE *error_log = NULL; @@ -604,6 +605,44 @@ void c_initialize_firsttime(void) { #if !TESTING && !defined(__APPLE__) && !defined(ANDROID) 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) { argc = _argc; argv = _argv; @@ -618,6 +657,17 @@ int main(int _argc, char **_argv) { pthread_create(&cpu_thread_id, NULL, (void *)&cpu_thread, (void *)NULL); 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 diff --git a/src/misc.h b/src/misc.h index 280ea164..fdc70aef 100644 --- a/src/misc.h +++ b/src/misc.h @@ -98,6 +98,8 @@ extern uint32_t softswitches; misc.c functions ------------------------------------------------------------------------- */ +extern bool emulator_shutting_down; + void c_initialize_firsttime(); void c_initialize_sound_hooks(); void c_disable_sound_hooks(); diff --git a/src/timing.c b/src/timing.c index ffc7ad42..e269c4e8 100644 --- a/src/timing.c +++ b/src/timing.c @@ -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(); } while (1); +#ifdef AUDIO_ENABLED + speaker_destroy(); + MB_Destroy(); + DSUninit(); +#endif + return NULL; } diff --git a/src/video/glvideo.c b/src/video/glvideo.c index c7c75fa2..831cc5d4 100644 --- a/src/video/glvideo.c +++ b/src/video/glvideo.c @@ -619,11 +619,9 @@ static void gldriver_init_common(void) { } } -static void gldriver_shutdown(void) { -#if USE_GLUT - glutDestroyWindow(glutWindow); -#endif +static void _gldriver_shutdown(void) { // Cleanup all OpenGL objects + emulator_shutting_down = true; glDeleteTextures(1, &a2TextureName); a2TextureName = UNINITIALIZED_GL; _destroy_VAO(crtVAOName); @@ -632,6 +630,15 @@ static void gldriver_shutdown(void) { glDeleteProgram(program); program = UNINITIALIZED_GL; 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) { #if USE_GLUT + glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_GLUTMAINLOOP_RETURNS); glutMainLoop(); + LOG("GLUT main loop finished..."); + _gldriver_shutdown(); #endif // fall through if not GLUT } diff --git a/valgrind.suppress b/valgrind.suppress new file mode 100644 index 00000000..71c88e7f --- /dev/null +++ b/valgrind.suppress @@ -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 +}