diff --git a/CMakeLists.txt b/CMakeLists.txt index 5299448f3..5db0f0108 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -64,6 +64,7 @@ option(MUNT "MUNT" ON) option(VRAMDUMP "Video RAM dumping" OFF) option(DINPUT "DirectInput" OFF) option(DISCORD "Discord integration" ON) +option(CPPTHRAD "C++11 threads" ON) option(NEW_DYNAREC "Use the PCem v15 (\"new\") dynamic recompiler" OFF) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f2d638c2c..142fdfabd 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -34,10 +34,14 @@ endif() # WIN32 marks us as a GUI app on Windows # MACOSX_BUNDLE prepares a macOS application bundle including with the app icon -add_executable(86Box WIN32 MACOSX_BUNDLE 86box.c config.c cpp11_thread.cpp log.c random.c timer.c io.c acpi.c apm.c +add_executable(86Box WIN32 MACOSX_BUNDLE 86box.c config.c log.c random.c timer.c io.c acpi.c apm.c dma.c ddma.c nmi.c pic.c pit.c port_6x.c port_92.c ppi.c pci.c mca.c usb.c device.c nvr.c nvr_at.c nvr_ps2.c rtmidi_midi.cpp ${APP_ICON_MACOSX}) +if(CPPTHREADS) + target_sources(plat PRIVATE cpp11_thread.cpp) +endif() + if(APPLE) target_link_libraries(86Box "-framework AppKit") endif() diff --git a/src/unix/CMakeLists.txt b/src/unix/CMakeLists.txt index e21265370..7cd52879b 100644 --- a/src/unix/CMakeLists.txt +++ b/src/unix/CMakeLists.txt @@ -8,7 +8,7 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") else() set(PLAT_SOURCES unix_midi.c) endif() -add_library(plat STATIC ${PLAT_SOURCES} unix_thread.c) +add_library(plat STATIC ${PLAT_SOURCES}) add_library(ui STATIC unix.c unix_sdl.c unix_cdrom.c) target_compile_definitions(ui PUBLIC _FILE_OFFSET_BITS=64) target_link_libraries(ui dl) @@ -28,6 +28,10 @@ if (ALSA_FOUND) target_link_libraries(plat ALSA::ALSA) endif() -set(THREADS_PREFER_PTHREAD_FLAG TRUE) -find_package(Threads REQUIRED) -target_link_libraries(86Box Threads::Threads) +if (NOT CPPTHREADS) + target_sources(plat PRIVATE unix_thread.c) + + set(THREADS_PREFER_PTHREAD_FLAG TRUE) + find_package(Threads REQUIRED) + target_link_libraries(86Box Threads::Threads) +endif() diff --git a/src/win/CMakeLists.txt b/src/win/CMakeLists.txt index 304ff8d68..9b0016e6f 100644 --- a/src/win/CMakeLists.txt +++ b/src/win/CMakeLists.txt @@ -23,6 +23,10 @@ add_library(ui OBJECT win_ui.c win_icon.c win_stbar.c win_sdl.c win_dialog.c win win_jsconf.c win_media_menu.c win_preferences.c win_discord.c glad.c win_opengl.c win_opengl_glslp.c 86Box.rc) +if(NOT CPPTHREADS) + target_sources(plat PRIVATE win_thread.c) +endif() + if(MSVC) # MSVC complains when we include the manifest from 86Box.rc... # On the bright side, CMake supports passing the manifest as a source diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index 4ef41f2e6..d7bf837da 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -163,6 +163,9 @@ endif ifndef DYNAREC DYNAREC := y endif +ifndef CPPTHREADS + CPPTHREADS := cpp11 +endif ifeq ($(DYNAREC), y) ifeq ($(ARM), y) ifeq ($(NEW_DYNAREC), n) @@ -370,6 +373,12 @@ MUNTOBJ := midi_mt32.o \ Synth.o Tables.o TVA.o TVF.o TVP.o sha1.o c_interface.o endif +ifeq ($(CPPTHREADS), y) +THREADOBJ := cpp11_thread.o +else +THREADOBJ := win_thread.o +endif + ifeq ($(VNC), y) OPTS += -DUSE_VNC RFLAGS += -DUSE_VNC @@ -464,7 +473,7 @@ CXXFLAGS := $(CFLAGS) ######################################################################### # Create the (final) list of objects to build. # ######################################################################### -MAINOBJ := 86box.o config.o cpp11_thread.o log.o random.o timer.o io.o acpi.o apm.o dma.o ddma.o \ +MAINOBJ := 86box.o config.o log.o random.o timer.o io.o acpi.o apm.o dma.o ddma.o \ nmi.o pic.o pit.o port_6x.o port_92.o ppi.o pci.o mca.o \ usb.o device.o nvr.o nvr_at.o nvr_ps2.o rtmidi_midi.o \ $(VNCOBJ) @@ -693,7 +702,7 @@ endif OBJ := $(MAINOBJ) $(CPUOBJ) $(CHIPSETOBJ) $(MCHOBJ) $(DEVOBJ) $(MEMOBJ) \ $(FDDOBJ) $(GAMEOBJ) $(CDROMOBJ) $(ZIPOBJ) $(MOOBJ) $(HDDOBJ) $(MINIVHDOBJ) \ $(NETOBJ) $(PRINTOBJ) $(SCSIOBJ) $(SIOOBJ) $(SNDOBJ) $(VIDOBJ) $(VOODOOOBJ) \ - $(PLATOBJ) $(UIOBJ) $(FSYNTHOBJ) $(MUNTOBJ) $(DEVBROBJ) $(MINITRACEOBJ) + $(PLATOBJ) $(UIOBJ) $(FSYNTHOBJ) $(MUNTOBJ) $(DEVBROBJ) $(MINITRACEOBJ) $(THREADOBJ) ifdef EXOBJ OBJ += $(EXOBJ) endif diff --git a/src/win/win_thread.c b/src/win/win_thread.c new file mode 100644 index 000000000..f8d81fa86 --- /dev/null +++ b/src/win/win_thread.c @@ -0,0 +1,183 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implement threads and mutexes for the Win32 platform. + * + * + * + * Authors: Sarah Walker, + * Fred N. van Kempen, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#define UNICODE +#define BITMAP WINDOWS_BITMAP +#include +#include +#include +#undef BITMAP +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/plat.h> + + +typedef struct { + HANDLE handle; +} win_event_t; + + +thread_t * +thread_create(void (*func)(void *param), void *param) +{ + uintptr_t bt = _beginthread(func, 0, param); + return((thread_t *)bt); +} + + +int +thread_wait(thread_t *arg, int timeout) +{ + if (arg == NULL) return(0); + + if (timeout == -1) + timeout = INFINITE; + + if (WaitForSingleObject(arg, timeout)) return(1); + + return(0); +} + + +event_t * +thread_create_event(void) +{ + win_event_t *ev = malloc(sizeof(win_event_t)); + + ev->handle = CreateEvent(NULL, FALSE, FALSE, NULL); + + return((event_t *)ev); +} + + +void +thread_set_event(event_t *arg) +{ + win_event_t *ev = (win_event_t *)arg; + + if (arg == NULL) return; + + SetEvent(ev->handle); +} + + +void +thread_reset_event(event_t *arg) +{ + win_event_t *ev = (win_event_t *)arg; + + if (arg == NULL) return; + + ResetEvent(ev->handle); +} + + +int +thread_wait_event(event_t *arg, int timeout) +{ + win_event_t *ev = (win_event_t *)arg; + + if (arg == NULL) return(0); + + if (ev->handle == NULL) return(0); + + if (timeout == -1) + timeout = INFINITE; + + if (WaitForSingleObject(ev->handle, timeout)) return(1); + + return(0); +} + + +void +thread_destroy_event(event_t *arg) +{ + win_event_t *ev = (win_event_t *)arg; + + if (arg == NULL) return; + + CloseHandle(ev->handle); + + free(ev); +} + + +mutex_t * +thread_create_mutex(void) +{ + mutex_t *mutex = malloc(sizeof(CRITICAL_SECTION)); + + InitializeCriticalSection(mutex); + + return mutex; +} + + +mutex_t * +thread_create_mutex_with_spin_count(unsigned int spin_count) +{ + mutex_t *mutex = malloc(sizeof(CRITICAL_SECTION)); + + InitializeCriticalSectionAndSpinCount(mutex, spin_count); + + return mutex; +} + + +int +thread_wait_mutex(mutex_t *mutex) +{ + if (mutex == NULL) return(0); + + LPCRITICAL_SECTION critsec = (LPCRITICAL_SECTION)mutex; + + EnterCriticalSection(critsec); + + return 1; +} + + +int +thread_release_mutex(mutex_t *mutex) +{ + if (mutex == NULL) return(0); + + LPCRITICAL_SECTION critsec = (LPCRITICAL_SECTION)mutex; + + LeaveCriticalSection(critsec); + + return 1; +} + + +void +thread_close_mutex(mutex_t *mutex) +{ + if (mutex == NULL) return; + + LPCRITICAL_SECTION critsec = (LPCRITICAL_SECTION)mutex; + + DeleteCriticalSection(critsec); + + free(critsec); +}