diff --git a/.github/workflows/build-macos.yml b/.github/workflows/build-macos.yml index 14209baf..cd25e40c 100644 --- a/.github/workflows/build-macos.yml +++ b/.github/workflows/build-macos.yml @@ -4,12 +4,13 @@ on: push: branches: - master - - ci/vcpkg-update + - ci/* pull_request: branches: - master env: + VCPKG_COMMIT: 2ad004460f5db4d3b66f62f5799ff66c265c4b5d MELONDS_GIT_BRANCH: ${{ github.ref }} MELONDS_GIT_HASH: ${{ github.sha }} MELONDS_BUILD_PROVIDER: GitHub Actions @@ -34,7 +35,7 @@ jobs: - name: Set up vcpkg uses: lukka/run-vcpkg@v11 with: - vcpkgGitCommitId: 10b7a178346f3f0abef60cecd5130e295afd8da4 + vcpkgGitCommitId: ${{ env.VCPKG_COMMIT }} - name: Build uses: lukka/run-cmake@v10 with: diff --git a/.github/workflows/build-ubuntu.yml b/.github/workflows/build-ubuntu.yml index 2d985f34..d27346e4 100644 --- a/.github/workflows/build-ubuntu.yml +++ b/.github/workflows/build-ubuntu.yml @@ -4,6 +4,7 @@ on: push: branches: - master + - ci/* pull_request: branches: - master @@ -15,16 +16,24 @@ env: MELONDS_VERSION_SUFFIX: " RC" jobs: - build-x86_64: - name: x86_64 - runs-on: ubuntu-22.04 + build: + continue-on-error: true + strategy: + matrix: + arch: + - runner: ubuntu-22.04 + name: x86_64 + - runner: ubuntu-22.04-arm + name: aarch64 + + name: ${{ matrix.arch.name }} + runs-on: ${{ matrix.arch.runner }} steps: - uses: actions/checkout@v4 name: Check out sources - name: Install dependencies run: | - sudo rm -f /etc/apt/sources.list.d/dotnetdev.list /etc/apt/sources.list.d/microsoft-prod.list sudo apt update sudo apt install --allow-downgrades cmake ninja-build extra-cmake-modules libpcap0.8-dev libsdl2-dev libenet-dev \ qt6-{base,base-private,multimedia}-dev libqt6svg6-dev libarchive-dev libzstd-dev libfuse2 liblua5.4-dev @@ -36,21 +45,21 @@ jobs: DESTDIR=AppDir cmake --install build - uses: actions/upload-artifact@v4 with: - name: melonDS-ubuntu-x86_64 + name: melonDS-ubuntu-${{ matrix.arch.name }} path: AppDir/usr/bin/melonDS - name: Fetch AppImage tools run: | - wget https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage - wget https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage + wget https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-${{ matrix.arch.name }}.AppImage + wget https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-${{ matrix.arch.name }}.AppImage chmod a+x linuxdeploy-*.AppImage - name: Build the AppImage env: QMAKE: /usr/lib/qt6/bin/qmake run: | - ./linuxdeploy-x86_64.AppImage --appdir AppDir --plugin qt --output appimage + ./linuxdeploy-${{ matrix.arch.name }}.AppImage --appdir AppDir --plugin qt --output appimage - uses: actions/upload-artifact@v4 with: - name: melonDS-appimage-x86_64 + name: melonDS-appimage-${{ matrix.arch.name }} path: melonDS*.AppImage build-aarch64: diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index 077fb152..92d45d4d 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -10,6 +10,7 @@ on: - master env: + VCPKG_COMMIT: 2ad004460f5db4d3b66f62f5799ff66c265c4b5d MELONDS_GIT_BRANCH: ${{ github.ref }} MELONDS_GIT_HASH: ${{ github.sha }} MELONDS_BUILD_PROVIDER: GitHub Actions @@ -33,7 +34,7 @@ jobs: - name: Set up vcpkg uses: lukka/run-vcpkg@v11 with: - vcpkgGitCommitId: 10b7a178346f3f0abef60cecd5130e295afd8da4 + vcpkgGitCommitId: ${{ env.VCPKG_COMMIT }} - name: Configure run: cmake --preset=release-mingw-x86_64 -DMELONDS_EMBED_BUILD_INFO=ON - name: Build diff --git a/CMakeLists.txt b/CMakeLists.txt index c54b6450..531ca19f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,6 +9,7 @@ set(CMAKE_POLICY_DEFAULT_CMP0069 NEW) set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) set(CMAKE_USER_MAKE_RULES_OVERRIDE "${CMAKE_CURRENT_SOURCE_DIR}/cmake/DefaultBuildFlags.cmake") +set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum OS X deployment version") option(USE_VCPKG "Use vcpkg for dependency packages" OFF) if (USE_VCPKG) @@ -29,8 +30,6 @@ include(CheckIPOSupported) include(SetupCCache) include(Sanitizers) -set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum OS X deployment version") - set(CMAKE_C_STANDARD 11) set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD 17) diff --git a/cmake/ConfigureVcpkg.cmake b/cmake/ConfigureVcpkg.cmake index 3fb0786f..151e2989 100644 --- a/cmake/ConfigureVcpkg.cmake +++ b/cmake/ConfigureVcpkg.cmake @@ -9,7 +9,8 @@ if (VCPKG_ROOT STREQUAL "${_DEFAULT_VCPKG_ROOT}") endif() FetchContent_Declare(vcpkg GIT_REPOSITORY "https://github.com/Microsoft/vcpkg.git" - GIT_TAG 2024.10.21 + GIT_TAG 2ad004460f5db4d3b66f62f5799ff66c265c4b5d + EXCLUDE_FROM_ALL SOURCE_DIR "${CMAKE_SOURCE_DIR}/vcpkg") FetchContent_MakeAvailable(vcpkg) endif() diff --git a/flake.lock b/flake.lock index d7dd5bc6..85be38fa 100644 --- a/flake.lock +++ b/flake.lock @@ -5,11 +5,11 @@ "systems": "systems" }, "locked": { - "lastModified": 1726560853, - "narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=", + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", "owner": "numtide", "repo": "flake-utils", - "rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", "type": "github" }, "original": { @@ -20,11 +20,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1730531603, - "narHash": "sha256-Dqg6si5CqIzm87sp57j5nTaeBbWhHFaVyG7V6L8k3lY=", + "lastModified": 1739020877, + "narHash": "sha256-mIvECo/NNdJJ/bXjNqIh8yeoSjVLAuDuTUzAo7dzs8Y=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "7ffd9ae656aec493492b44d0ddfb28e79a1ea25d", + "rev": "a79cfe0ebd24952b580b1cf08cd906354996d547", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 97072b15..a65465dc 100644 --- a/flake.nix +++ b/flake.nix @@ -96,7 +96,13 @@ libtool ninja pkg-config + python3 ]; + + # Undo the SDK setup done by nixpkgs so we can use AppleClang + shellHook = '' + unset DEVELOPER_DIR SDKROOT MACOSX_DEPLOYMENT_TARGET + ''; }; }; } diff --git a/src/ARM.cpp b/src/ARM.cpp index 0d93dc45..f75c1e27 100644 --- a/src/ARM.cpp +++ b/src/ARM.cpp @@ -115,7 +115,7 @@ ARM::ARM(u32 num, bool jit, std::optional gdb, melonDS::NDS& nds) : Num(num), // well uh NDS(nds) { - SetGdbArgs(jit ? gdb : std::nullopt); + SetGdbArgs(jit ? std::nullopt : gdb); } ARM::~ARM() diff --git a/src/ARMJIT_A64/ARMJIT_Branch.cpp b/src/ARMJIT_A64/ARMJIT_Branch.cpp index f9c2e0c5..c83f8161 100644 --- a/src/ARMJIT_A64/ARMJIT_Branch.cpp +++ b/src/ARMJIT_A64/ARMJIT_Branch.cpp @@ -83,7 +83,7 @@ void Compiler::Comp_JumpTo(u32 addr, bool forceNonConstantCycles) // doesn't matter if we put garbage in the MSbs there if (addr & 0x2) { - cpu9->CodeRead32(addr-2, true) >> 16; + cpu9->CodeRead32(addr-2, true); cycles += cpu9->CodeCycles; cpu9->CodeRead32(addr+2, false); cycles += CurCPU->CodeCycles; @@ -437,4 +437,4 @@ void Compiler::T_Comp_BL_Merged() Comp_JumpTo(target); } -} \ No newline at end of file +} diff --git a/src/ARMJIT_Memory.cpp b/src/ARMJIT_Memory.cpp index e1c1da43..66838918 100644 --- a/src/ARMJIT_Memory.cpp +++ b/src/ARMJIT_Memory.cpp @@ -900,7 +900,7 @@ ARMJIT_Memory::ARMJIT_Memory(melonDS::NDS& nds) : NDS(nds) } #else char fastmemPidName[snprintf(NULL, 0, "/melondsfastmem%d", getpid()) + 1]; - sprintf(fastmemPidName, "/melondsfastmem%d", getpid()); + snprintf(fastmemPidName, sizeof(fastmemPidName), "/melondsfastmem%d", getpid()); MemoryFile = shm_open(fastmemPidName, O_RDWR | O_CREAT | O_EXCL, 0600); if (MemoryFile == -1) { @@ -951,7 +951,6 @@ ARMJIT_Memory::~ARMJIT_Memory() noexcept MemoryBase = nullptr; FastMem9Start = nullptr; FastMem7Start = nullptr; - printf("unmappinged everything\n"); } if (MemoryFile) @@ -979,6 +978,8 @@ ARMJIT_Memory::~ARMJIT_Memory() noexcept MemoryFile = -1; } + Log(LogLevel::Info, "unmappinged everything\n"); + #if defined(__ANDROID__) if (Libandroid) { @@ -1599,4 +1600,4 @@ void* ARMJIT_Memory::GetFuncForAddr(ARM* cpu, u32 addr, bool store, int size) co } return NULL; } -} \ No newline at end of file +} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fa8d475c..fef78706 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -102,6 +102,8 @@ if (ENABLE_JIT) dolphin/CommonFuncs.cpp) if (WIN32) + # Required for memory mapping-related functions introduced in Windows 8 + target_compile_definitions(core PRIVATE -D_WIN32_WINNT=_WIN32_WINNT_WIN8) target_link_libraries(core PRIVATE onecore) endif() diff --git a/src/GBACart.cpp b/src/GBACart.cpp index c3550207..be0d223b 100644 --- a/src/GBACart.cpp +++ b/src/GBACart.cpp @@ -539,6 +539,57 @@ CartGameSolarSensor::CartGameSolarSensor(std::unique_ptr&& rom, u32 len, s { } +std::unique_ptr CreateFakeSolarSensorROM(const char* gamecode, const NDSCart::CartCommon& cart, void* userdata) noexcept +{ + return CreateFakeSolarSensorROM(gamecode, cart.GetHeader().NintendoLogo, userdata); +} + +std::unique_ptr CreateFakeSolarSensorROM(const char* gamecode, const GBACart::CartGame& cart, void* userdata) noexcept +{ + return CreateFakeSolarSensorROM(gamecode, cart.GetHeader().NintendoLogo, userdata); +} + +std::unique_ptr CreateFakeSolarSensorROM(const char* gamecode, const u8* logo, void* userdata) noexcept +{ + if (!gamecode) + return nullptr; + + if (strnlen(gamecode, sizeof(GBAHeader::GameCode)) > sizeof(GBAHeader::GameCode)) + return nullptr; + + bool solarsensor = false; + for (const char* i : SOLAR_SENSOR_GAMECODES) + { + if (strcmp(gamecode, i) == 0) { + solarsensor = true; + break; + } + } + + if (!solarsensor) + return nullptr; + + // just 256 bytes; we don't need a whole ROM! + constexpr size_t FAKE_BOKTAI_ROM_LENGTH = 0x100; + std::unique_ptr rom = std::make_unique(FAKE_BOKTAI_ROM_LENGTH); + + // create a fake ROM + GBAHeader& header = *reinterpret_cast(rom.get()); + memcpy(header.Title, BOKTAI_STUB_TITLE, strnlen(BOKTAI_STUB_TITLE, sizeof(header.Title))); + memcpy(header.GameCode, gamecode, strnlen(gamecode, sizeof(header.GameCode))); + header.FixedValue = 0x96; + if (logo) + { + memcpy(header.NintendoLogo, logo, sizeof(header.NintendoLogo)); + } + else + { + memset(header.NintendoLogo, 0xFF, sizeof(header.NintendoLogo)); + } + + return std::make_unique(std::move(rom), FAKE_BOKTAI_ROM_LENGTH, nullptr, 0, userdata); +} + const int CartGameSolarSensor::kLuxLevels[11] = {0, 5, 11, 18, 27, 42, 62, 84, 109, 139, 183}; void CartGameSolarSensor::Reset() @@ -843,7 +894,18 @@ std::unique_ptr LoadAddon(int type, void* userdata) case GBAAddon_RumblePak: cart = std::make_unique(userdata); break; - + case GBAAddon_SolarSensorBoktai1: + // US Boktai 1 + cart = CreateFakeSolarSensorROM("U3IE", nullptr, userdata); + break; + case GBAAddon_SolarSensorBoktai2: + // US Boktai 2 + cart = CreateFakeSolarSensorROM("U32E", nullptr, userdata); + break; + case GBAAddon_SolarSensorBoktai3: + // JP Boktai 3 + cart = CreateFakeSolarSensorROM("U33J", nullptr, userdata); + break; default: Log(LogLevel::Warn, "GBACart: !! invalid addon type %d\n", type); return nullptr; diff --git a/src/GBACart.h b/src/GBACart.h index e6639813..c9a7caa9 100644 --- a/src/GBACart.h +++ b/src/GBACart.h @@ -35,6 +35,25 @@ enum CartType RumblePak = 0x202, }; +// See https://problemkaputt.de/gbatek.htm#gbacartridgeheader for details +struct GBAHeader +{ + u32 EntryPoint; + u8 NintendoLogo[156]; // must be valid + char Title[12]; + char GameCode[4]; + char MakerCode[2]; + u8 FixedValue; // must be 0x96 + u8 MainUnitCode; + u8 DeviceType; + u8 Reserved0[7]; + u8 SoftwareVersion; + u8 ComplementCheck; + u8 Reserved1[2]; +}; + +static_assert(sizeof(GBAHeader) == 192, "GBAHeader should be 192 bytes"); + // CartCommon -- base code shared by all cart types class CartCommon { @@ -91,6 +110,8 @@ public: [[nodiscard]] const u8* GetROM() const override { return ROM.get(); } [[nodiscard]] u32 GetROMLength() const override { return ROMLength; } + [[nodiscard]] const GBAHeader& GetHeader() const noexcept { return *reinterpret_cast(ROM.get()); } + [[nodiscard]] GBAHeader& GetHeader() noexcept { return *reinterpret_cast(ROM.get()); } u8* GetSaveMemory() const override; u32 GetSaveMemoryLength() const override; @@ -309,6 +330,23 @@ std::unique_ptr ParseROM(std::unique_ptr&& romdata, u32 romlen std::unique_ptr LoadAddon(int type, void* userdata); +/// Creates a solar sensor-enabled GBA cart without needing a real Boktai ROM. +/// This enables the solar sensor to be used in supported games. +/// Will not contain any SRAM. +/// @param gamecode +/// @param logo The Nintendo logo data embedded in the headers for GBA ROMs and NDS ROMs. +/// Required for the cart to be recognized as a valid GBA cart. +/// Overloads that accept cart objects directly exist as well. +/// If not provided, then it will have to be patched with equivalent data +/// from a real ROM (NDS or GBA) before booting the emulator. +/// @param userdata Optional user data to associate with the cart. +/// @return A CartGameSolarSensor if the ROM was created successfully, +/// or nullptr if any argument is wrong (e.g. an incorrect game code). +std::unique_ptr CreateFakeSolarSensorROM(const char* gamecode, const u8* logo, void* userdata = nullptr) noexcept; +std::unique_ptr CreateFakeSolarSensorROM(const char* gamecode, const NDSCart::CartCommon& cart, void* userdata = nullptr) noexcept; +std::unique_ptr CreateFakeSolarSensorROM(const char* gamecode, const GBACart::CartGame& cart, void* userdata = nullptr) noexcept; + +constexpr const char* BOKTAI_STUB_TITLE = "BOKTAI STUB"; } #endif // GBACART_H diff --git a/src/NDS.cpp b/src/NDS.cpp index 7cef3bf0..2efb3b0a 100644 --- a/src/NDS.cpp +++ b/src/NDS.cpp @@ -546,6 +546,26 @@ void NDS::Reset() void NDS::Start() { Running = true; + + if (ConsoleType != 0) + return; + + auto* ndscart = NDSCartSlot.GetCart(); + if (!ndscart) + return; + + if (auto* cart = GBACartSlot.GetCart(); cart && cart->Type() == GBACart::CartType::GameSolarSensor) + { // If we have a solar sensor cart inserted... + auto& solarcart = *static_cast(cart); + GBACart::GBAHeader& header = solarcart.GetHeader(); + if (strncmp(header.Title, GBACart::BOKTAI_STUB_TITLE, sizeof(header.Title)) == 0) { + // If this is a stub Boktai cart (so we can use the sensor without a full ROM)... + + // ...then copy the Nintendo logo data from the NDS ROM into the stub GBA ROM. + // Otherwise, the GBA cart won't be recognized. + memcpy(header.NintendoLogo, ndscart->GetHeader().NintendoLogo, sizeof(header.NintendoLogo)); + } + } } static const char* StopReasonName(Platform::StopReason reason) @@ -875,7 +895,7 @@ void NDS::RunSystemSleep(u64 timestamp) param = evt.Param; EventFunc func = evt.Funcs[evt.FuncID]; - func(this, param); + func(evt.That, param); } } } diff --git a/src/NDS.h b/src/NDS.h index 6e486e28..8efbb90c 100644 --- a/src/NDS.h +++ b/src/NDS.h @@ -215,6 +215,12 @@ enum { GBAAddon_RAMExpansion = 1, GBAAddon_RumblePak = 2, + // Each game in the GBA Boktai trilogy uses the same solar sensor, + // but Lunar Knights (the only NDS game to use the solar sensor) + // applies slightly different effects depending on the game. + GBAAddon_SolarSensorBoktai1 = 3, + GBAAddon_SolarSensorBoktai2 = 4, + GBAAddon_SolarSensorBoktai3 = 5, }; class SPU; diff --git a/src/frontend/qt_sdl/CMakeLists.txt b/src/frontend/qt_sdl/CMakeLists.txt index 67947807..fa946fd9 100644 --- a/src/frontend/qt_sdl/CMakeLists.txt +++ b/src/frontend/qt_sdl/CMakeLists.txt @@ -215,8 +215,6 @@ if (WIN32) endif() if (APPLE) - target_sources(melonDS PRIVATE sem_timedwait.cpp) - # Copy icon into the bundle set(RESOURCE_FILES "${CMAKE_SOURCE_DIR}/res/melon.icns") target_sources(melonDS PUBLIC "${RESOURCE_FILES}") diff --git a/src/frontend/qt_sdl/CameraManager.cpp b/src/frontend/qt_sdl/CameraManager.cpp index 2306da84..687d7b4b 100644 --- a/src/frontend/qt_sdl/CameraManager.cpp +++ b/src/frontend/qt_sdl/CameraManager.cpp @@ -59,6 +59,8 @@ void CameraFrameDumper::present(const QVideoFrame& _frame) case QVideoFrameFormat::Format_NV12: cam->feedFrame_NV12((u8*)frame.bits(0), (u8*)frame.bits(1), frame.width(), frame.height()); break; + default: + break; } frame.unmap(); diff --git a/src/frontend/qt_sdl/DateTimeDialog.h b/src/frontend/qt_sdl/DateTimeDialog.h index 9763f306..5057609f 100644 --- a/src/frontend/qt_sdl/DateTimeDialog.h +++ b/src/frontend/qt_sdl/DateTimeDialog.h @@ -58,7 +58,7 @@ protected: void timerEvent(QTimerEvent* event) override; private slots: - void done(int r); + void done(int r) override; void on_chkChangeTime_clicked(bool checked); void on_chkResetTime_clicked(bool checked); diff --git a/src/frontend/qt_sdl/EmuInstance.cpp b/src/frontend/qt_sdl/EmuInstance.cpp index 309abe66..eb11ede2 100644 --- a/src/frontend/qt_sdl/EmuInstance.cpp +++ b/src/frontend/qt_sdl/EmuInstance.cpp @@ -1082,13 +1082,13 @@ std::optional EmuInstance::loadNAND(const std::array, char16_t>{}; + //auto converter = wstring_convert, char16_t>{}; // setting up username - std::u16string username = converter.from_bytes(firmcfg.GetString("Username")); - size_t usernameLength = std::min(username.length(), (size_t) 10); + auto username = firmcfg.GetQString("Username"); + size_t usernameLength = std::min((int) username.length(), 10); memset(&settings.Nickname, 0, sizeof(settings.Nickname)); - memcpy(&settings.Nickname, username.data(), usernameLength * sizeof(char16_t)); + memcpy(&settings.Nickname, username.utf16(), usernameLength * sizeof(char16_t)); // setting language settings.Language = static_cast(firmcfg.GetInt("Language")); @@ -1101,10 +1101,10 @@ std::optional EmuInstance::loadNAND(const std::array gdbargs = std::nullopt; + std::optional gdbargs = std::nullopt; #endif NDSArgs ndsargs { @@ -1670,14 +1670,12 @@ void EmuInstance::customizeFirmware(Firmware& firmware, bool overridesettings) n auto firmcfg = localCfg.GetTable("Firmware"); // setting up username - std::string orig_username = firmcfg.GetString("Username"); - if (!orig_username.empty()) + auto username = firmcfg.GetQString("Username"); + if (!username.isEmpty()) { // If the frontend defines a username, take it. If not, leave the existing one. - std::u16string username = std::wstring_convert, char16_t>{}.from_bytes( - orig_username); - size_t usernameLength = std::min(username.length(), (size_t) 10); + size_t usernameLength = std::min((int) username.length(), 10); currentData.NameLength = usernameLength; - memcpy(currentData.Nickname, username.data(), usernameLength * sizeof(char16_t)); + memcpy(currentData.Nickname, username.utf16(), usernameLength * sizeof(char16_t)); } auto language = static_cast(firmcfg.GetInt("Language")); @@ -1707,12 +1705,10 @@ void EmuInstance::customizeFirmware(Firmware& firmware, bool overridesettings) n } // setup message - std::string orig_message = firmcfg.GetString("Message"); - if (!orig_message.empty()) + auto message = firmcfg.GetQString("Message"); + if (!message.isEmpty()) { - std::u16string message = std::wstring_convert, char16_t>{}.from_bytes( - orig_message); - size_t messageLength = std::min(message.length(), (size_t) 26); + size_t messageLength = std::min((int) message.length(), 26); currentData.MessageLength = messageLength; memcpy(currentData.Message, message.data(), messageLength * sizeof(char16_t)); } @@ -2146,6 +2142,12 @@ QString EmuInstance::gbaAddonName(int addon) return "Rumble Pak"; case GBAAddon_RAMExpansion: return "Memory expansion"; + case GBAAddon_SolarSensorBoktai1: + return "Solar Sensor (Boktai 1)"; + case GBAAddon_SolarSensorBoktai2: + return "Solar Sensor (Boktai 2)"; + case GBAAddon_SolarSensorBoktai3: + return "Solar Sensor (Boktai 3)"; } return "???"; diff --git a/src/frontend/qt_sdl/EmuInstanceAudio.cpp b/src/frontend/qt_sdl/EmuInstanceAudio.cpp index a4ac9394..21e573f9 100644 --- a/src/frontend/qt_sdl/EmuInstanceAudio.cpp +++ b/src/frontend/qt_sdl/EmuInstanceAudio.cpp @@ -29,7 +29,7 @@ using namespace melonDS; int EmuInstance::audioGetNumSamplesOut(int outlen) { - float f_len_in = (outlen * 32823.6328125) / (float)audioFreq; + float f_len_in = (outlen * 32823.6328125 * (curFPS/60.0)) / (float)audioFreq; f_len_in += audioSampleFrac; int len_in = (int)floor(f_len_in); audioSampleFrac = f_len_in - len_in; @@ -73,6 +73,7 @@ void EmuInstance::audioCallback(void* data, Uint8* stream, int len) // resample incoming audio to match the output sample rate int len_in = inst->audioGetNumSamplesOut(len); + if (len_in > 1024) len_in = 1024; s16 buf_in[1024*2]; int num_in; diff --git a/src/frontend/qt_sdl/EmuThread.cpp b/src/frontend/qt_sdl/EmuThread.cpp index 825edf40..0efa5f1d 100644 --- a/src/frontend/qt_sdl/EmuThread.cpp +++ b/src/frontend/qt_sdl/EmuThread.cpp @@ -366,7 +366,7 @@ void EmuThread::run() if (slowmo) emuInstance->curFPS = emuInstance->slowmoFPS; else if (fastforward) emuInstance->curFPS = emuInstance->fastForwardFPS; - else if (!emuInstance->doLimitFPS) emuInstance->curFPS = 1000.0; + else if (!emuInstance->doLimitFPS && !emuInstance->doAudioSync) emuInstance->curFPS = 1000.0; else emuInstance->curFPS = emuInstance->targetFPS; if (emuInstance->audioDSiVolumeSync && emuInstance->nds->ConsoleType == 1) @@ -389,6 +389,7 @@ void EmuThread::run() if (frametimeStep < 0.001) frametimeStep = 0.001; + if (emuInstance->doLimitFPS) { double curtime = SDL_GetPerformanceCounter() * perfCountsSec; @@ -428,9 +429,9 @@ void EmuThread::run() double actualfps = (59.8261 * 263.0) / nlines; int inst = emuInstance->instanceID; if (inst == 0) - sprintf(melontitle, "[%d/%.0f] melonDS " MELONDS_VERSION, fps, actualfps); + snprintf(melontitle, sizeof(melontitle), "[%d/%.0f] melonDS " MELONDS_VERSION, fps, actualfps); else - sprintf(melontitle, "[%d/%.0f] melonDS (%d)", fps, fpstarget, inst+1); + snprintf(melontitle, sizeof(melontitle), "[%d/%.0f] melonDS (%d)", fps, actualfps, inst+1); changeWindowTitle(melontitle); } } @@ -445,9 +446,9 @@ void EmuThread::run() int inst = emuInstance->instanceID; if (inst == 0) - sprintf(melontitle, "melonDS " MELONDS_VERSION); + snprintf(melontitle, sizeof(melontitle), "melonDS " MELONDS_VERSION); else - sprintf(melontitle, "melonDS (%d)", inst+1); + snprintf(melontitle, sizeof(melontitle), "melonDS (%d)", inst+1); changeWindowTitle(melontitle); SDL_Delay(75); diff --git a/src/frontend/qt_sdl/LANDialog.cpp b/src/frontend/qt_sdl/LANDialog.cpp index bec9c48f..6707cfdc 100644 --- a/src/frontend/qt_sdl/LANDialog.cpp +++ b/src/frontend/qt_sdl/LANDialog.cpp @@ -403,6 +403,8 @@ void LANDialog::doUpdatePlayerList() case LAN::Player_Disconnected: status = "Connection lost"; break; + case LAN::Player_None: + break; } model->item(i, 2)->setText(status); diff --git a/src/frontend/qt_sdl/LANDialog.h b/src/frontend/qt_sdl/LANDialog.h index 03857d79..0a65a6e9 100644 --- a/src/frontend/qt_sdl/LANDialog.h +++ b/src/frontend/qt_sdl/LANDialog.h @@ -48,7 +48,7 @@ public: } private slots: - void done(int r); + void done(int r) override; private: Ui::LANStartHostDialog* ui; @@ -76,7 +76,7 @@ private slots: void onGameSelectionChanged(const QItemSelection& cur, const QItemSelection& prev); void on_tvAvailableGames_doubleClicked(QModelIndex index); void onDirectConnect(); - void done(int r); + void done(int r) override; void doUpdateDiscoveryList(); @@ -105,7 +105,7 @@ protected: private slots: void on_btnLeaveGame_clicked(); - void done(int r); + void done(int r) override; void doUpdatePlayerList(); diff --git a/src/frontend/qt_sdl/MPSettingsDialog.h b/src/frontend/qt_sdl/MPSettingsDialog.h index 0fccb1c9..64b56579 100644 --- a/src/frontend/qt_sdl/MPSettingsDialog.h +++ b/src/frontend/qt_sdl/MPSettingsDialog.h @@ -54,7 +54,7 @@ public: } private slots: - void done(int r); + void done(int r) override; // diff --git a/src/frontend/qt_sdl/NetplayDialog.cpp b/src/frontend/qt_sdl/NetplayDialog.cpp index d7b7cf81..3657eef8 100644 --- a/src/frontend/qt_sdl/NetplayDialog.cpp +++ b/src/frontend/qt_sdl/NetplayDialog.cpp @@ -187,7 +187,7 @@ void NetplayDialog::doUpdatePlayerList(Netplay::Player* players, int num) char ip[32]; u32 addr = player->Address; - sprintf(ip, "%d.%d.%d.%d", addr&0xFF, (addr>>8)&0xFF, (addr>>16)&0xFF, addr>>24); + snprintf(ip, sizeof(ip), "%d.%d.%d.%d", addr&0xFF, (addr>>8)&0xFF, (addr>>16)&0xFF, addr>>24); model->setItem(i, 4, new QStandardItem(ip)); } } diff --git a/src/frontend/qt_sdl/Screen.cpp b/src/frontend/qt_sdl/Screen.cpp index 98a7ed95..5c671f39 100644 --- a/src/frontend/qt_sdl/Screen.cpp +++ b/src/frontend/qt_sdl/Screen.cpp @@ -900,7 +900,7 @@ bool ScreenPanelGL::createContext() if (ourwin->getWindowID() != 0) { if (windowinfo.has_value()) - if (glContext = parentwin->getOGLContext()->CreateSharedContext(*windowinfo)) + if ((glContext = parentwin->getOGLContext()->CreateSharedContext(*windowinfo))) glContext->DoneCurrent(); } else @@ -909,7 +909,7 @@ bool ScreenPanelGL::createContext() GL::Context::Version{GL::Context::Profile::Core, 4, 3}, GL::Context::Version{GL::Context::Profile::Core, 3, 2}}; if (windowinfo.has_value()) - if (glContext = GL::Context::Create(*windowinfo, versionsToTry)) + if ((glContext = GL::Context::Create(*windowinfo, versionsToTry))) glContext->DoneCurrent(); } diff --git a/src/frontend/qt_sdl/TitleManagerDialog.cpp b/src/frontend/qt_sdl/TitleManagerDialog.cpp index 30f29d24..844365e7 100644 --- a/src/frontend/qt_sdl/TitleManagerDialog.cpp +++ b/src/frontend/qt_sdl/TitleManagerDialog.cpp @@ -119,13 +119,14 @@ void TitleManagerDialog::createTitleItem(u32 category, u32 titleid) // TODO: make it possible to select other languages? QString title = QString::fromUtf16(banner.EnglishTitle, 128); + title = title.left(title.indexOf('\0')); title.replace("\n", " · "); char gamecode[5]; *(u32*)&gamecode[0] = *(u32*)&header.GameCode[0]; gamecode[4] = '\0'; char extra[128]; - sprintf(extra, "\n(title ID: %s · %08x/%08x · version %08x)", gamecode, category, titleid, version); + snprintf(extra, sizeof(extra), "\n(title ID: %s · %08x/%08x · version %08x)", gamecode, category, titleid, version); QListWidgetItem* item = new QListWidgetItem(title + QString(extra)); item->setIcon(icon); @@ -481,7 +482,7 @@ void TitleImportDialog::accept() network = new QNetworkAccessManager(this); char url[256]; - sprintf(url, "http://nus.cdn.t.shop.nintendowifi.net/ccs/download/%08x%08x/tmd", titleid[1], titleid[0]); + snprintf(url, sizeof(url), "http://nus.cdn.t.shop.nintendowifi.net/ccs/download/%08x%08x/tmd", titleid[1], titleid[0]); QNetworkRequest req; req.setUrl(QUrl(url)); diff --git a/src/frontend/qt_sdl/WifiSettingsDialog.cpp b/src/frontend/qt_sdl/WifiSettingsDialog.cpp index e0954c83..e041234b 100644 --- a/src/frontend/qt_sdl/WifiSettingsDialog.cpp +++ b/src/frontend/qt_sdl/WifiSettingsDialog.cpp @@ -152,14 +152,14 @@ void WifiSettingsDialog::on_cbxDirectAdapter_currentIndexChanged(int sel) melonDS::AdapterData* adapter = &adapters[sel]; char tmp[64]; - sprintf(tmp, "%02X:%02X:%02X:%02X:%02X:%02X", - adapter->MAC[0], adapter->MAC[1], adapter->MAC[2], - adapter->MAC[3], adapter->MAC[4], adapter->MAC[5]); + snprintf(tmp, sizeof(tmp), "%02X:%02X:%02X:%02X:%02X:%02X", + adapter->MAC[0], adapter->MAC[1], adapter->MAC[2], + adapter->MAC[3], adapter->MAC[4], adapter->MAC[5]); ui->lblAdapterMAC->setText(QString(tmp)); - sprintf(tmp, "%d.%d.%d.%d", - adapter->IP_v4[0], adapter->IP_v4[1], - adapter->IP_v4[2], adapter->IP_v4[3]); + snprintf(tmp, sizeof(tmp), "%d.%d.%d.%d", + adapter->IP_v4[0], adapter->IP_v4[1], + adapter->IP_v4[2], adapter->IP_v4[3]); ui->lblAdapterIP->setText(QString(tmp)); } diff --git a/src/frontend/qt_sdl/Window.cpp b/src/frontend/qt_sdl/Window.cpp index 866f2d35..6c1ef1fd 100644 --- a/src/frontend/qt_sdl/Window.cpp +++ b/src/frontend/qt_sdl/Window.cpp @@ -322,7 +322,7 @@ MainWindow::MainWindow(int id, EmuInstance* inst, QWidget* parent) : QMenu * submenu = menu->addMenu("Insert add-on cart"); QAction *act; - int addons[] = {GBAAddon_RAMExpansion, GBAAddon_RumblePak, -1}; + int addons[] = {GBAAddon_RAMExpansion, GBAAddon_RumblePak, GBAAddon_SolarSensorBoktai1, GBAAddon_SolarSensorBoktai2, GBAAddon_SolarSensorBoktai3, -1}; for (int i = 0; addons[i] != -1; i++) { int addon = addons[i]; diff --git a/src/frontend/qt_sdl/sem_timedwait.cpp b/src/frontend/qt_sdl/sem_timedwait.cpp deleted file mode 100644 index 38b3c16f..00000000 --- a/src/frontend/qt_sdl/sem_timedwait.cpp +++ /dev/null @@ -1,488 +0,0 @@ -/* - * s e m _ t i m e d w a i t - * - * Function: - * Implements a version of sem_timedwait(). - * - * Description: - * Not all systems implement sem_timedwait(), which is a version of - * sem_wait() with a timeout. Mac OS X is one example, at least up to - * and including version 10.6 (Leopard). If such a function is needed, - * this code provides a reasonable implementation, which I think is - * compatible with the standard version, although possibly less - * efficient. It works by creating a thread that interrupts a normal - * sem_wait() call after the specified timeout. - * - * Call: - * - * The Linux man pages say: - * - * #include - * - * int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout); - * - * sem_timedwait() is the same as sem_wait(), except that abs_timeout - * specifies a limit on the amount of time that the call should block if - * the decrement cannot be immediately performed. The abs_timeout argument - * points to a structure that specifies an absolute timeout in seconds and - * nanoseconds since the Epoch (00:00:00, 1 January 1970). This structure - * is defined as follows: - * - * struct timespec { - * time_t tv_sec; Seconds - * long tv_nsec; Nanoseconds [0 .. 999999999] - * }; - * - * If the timeout has already expired by the time of the call, and the - * semaphore could not be locked immediately, then sem_timedwait() fails - * with a timeout error (errno set to ETIMEDOUT). - * If the operation can be performed immediately, then sem_timedwait() - * never fails with a timeout error, regardless of the value of abs_timeout. - * Furthermore, the validity of abs_timeout is not checked in this case. - * - * Limitations: - * - * The mechanism used involves sending a SIGUSR2 signal to the thread - * calling sem_timedwait(). The handler for this signal is set to a null - * routine which does nothing, and with any flags for the signal - * (eg SA_RESTART) cleared. Note that this effective disabling of the - * SIGUSR2 signal is a side-effect of using this routine, and means it - * may not be a completely transparent plug-in replacement for a - * 'normal' sig_timedwait() call. Since OS X does not declare the - * sem_timedwait() call in its standard include files, the relevant - * declaration (shown above in the man pages extract) will probably have - * to be added to any code that uses this. - * - * Compiling: - * This compiles and runs cleanly on OS X (10.6) with gcc with the - * -Wall -ansi -pedantic flags. On Linux, using -ansi causes a sweep of - * compiler complaints about the timespec structure, but it compiles - * and works fine with just -Wall -pedantic. (Since Linux provides - * sem_timedwait() anyway, this really isn't needed on Linux.) However, - * since Linux provides sem_timedwait anyway, the sem_timedwait() - * code in this file is only compiled on OS X, and is a null on other - * systems. - * - * Testing: - * This file contains a test program that exercises the sem_timedwait - * code. It is compiled if the pre-processor variable TEST is defined. - * For more details, see the comments for the test routine at the end - * of the file. - * - * Author: Keith Shortridge, AAO. - * - * History: - * 8th Sep 2009. Original version. KS. - * 24th Sep 2009. Added test that the calling thread still exists before - * trying to set the timed-out flag. KS. - * 2nd Oct 2009. No longer restores the original SIGUSR2 signal handler. - * See comments in the body of the code for more details. - * Prototypes for now discontinued internal routines removed. - * 12th Aug 2010. Added the cleanup handler, so that this code no longer - * leaks resources if the calling thread is cancelled. KS. - * 21st Sep 2011. Added copyright notice below. Modified header comments - * to describe the use of SIGUSR2 more accurately in the - * light of the 2/10/09 change above. Now undefs DEBUG - * before defining it, to avoid any possible clash. KS. - * 14th Feb 2012. Tidied out a number of TABs that had got into the - * code. KS. - * 6th May 2013. Copyright notice modified to one based on the MIT licence, - * which is more permissive than the previous notice. KS. - * - * Copyright (c) Australian Astronomical Observatory (AAO), (2013). - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#ifdef __APPLE__ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "sem_timedwait.h" - -/* Some useful definitions - TRUE, FALSE, and DEBUG */ - -#undef TRUE -#define TRUE 1 -#undef FALSE -#define FALSE 0 -#undef DEBUG -#define DEBUG printf - -/* A structure of type timeoutDetails is passed to the thread used to - * implement the timeout. - */ - -typedef struct { - struct timespec delay; /* Specifies the delay, relative to now */ - pthread_t callingThread; /* The thread doing the sem_wait call */ - volatile short *timedOutShort; /* Address of a flag set to indicate that - * the timeout was triggered. */ -} timeoutDetails; - -/* A structure of type cleanupDetails is passed to the thread cleanup - * routine which is called at the end of the routine or if the thread calling - * it is cancelled. - */ - -typedef struct { - pthread_t *threadIdAddr; /* Address of the variable that holds - * the Id of the timeout thread. */ - struct sigaction *sigHandlerAddr; /* Address of the old signal action - * handler. */ - volatile short *timedOutShort; /* Address of a flag set to indicate that - * the timeout was triggered. */ -} cleanupDetails; - -/* Forward declarations of internal routines */ - -static void* timeoutThreadMain (void* passedPtr); -static int triggerSignal (int Signal, pthread_t Thread); -static void ignoreSignal (int Signal); -static void timeoutThreadCleanup (void* passedPtr); - -/* -------------------------------------------------------------------------- */ -/* - * s e m _ t i m e d w a i t - * - * This is the main code for the sem_timedwait() implementation. - */ - -int sem_timedwait ( - sem_t *sem, - const struct timespec *abs_timeout) -{ - int result = 0; /* Code returned by this routine 0 or -1 */ - - /* "Under no circumstances shall the function fail if the semaphore - * can be locked immediately". So we try to get it quickly to see if we - * can avoid all the timeout overheads. - */ - - if (sem_trywait(sem) == 0) { - - /* Yes, got it immediately. */ - - result = 0; - - } else { - - /* No, we've got to do it with a sem_wait() call and a thread to run - * the timeout. First, work out the time from now to the specified - * timeout, which we will pass to the timeout thread in a way that can - * be used to pass to nanosleep(). So we need this in seconds and - * nanoseconds. Along the way, we check for an invalid passed time, - * and for one that's already expired. - */ - - if ((abs_timeout->tv_nsec < 0) || (abs_timeout->tv_nsec > 1000000000)) { - - /* Passed time is invalid */ - - result = -1; - errno = EINVAL; - - } else { - - struct timeval currentTime; /* Time now */ - long secsToWait,nsecsToWait; /* Seconds and nsec to delay */ - gettimeofday (¤tTime,NULL); - secsToWait = abs_timeout->tv_sec - currentTime.tv_sec; - nsecsToWait = (abs_timeout->tv_nsec - (currentTime.tv_usec * 1000)); - while (nsecsToWait < 0) { - nsecsToWait += 1000000000; - secsToWait--; - } - if ((secsToWait < 0) || ((secsToWait == 0) && (nsecsToWait < 0))) { - - /* Time has passed. Report an immediate timeout. */ - - result = -1; - errno = ETIMEDOUT; - - } else { - - /* We're going to have to do a sem_wait() with a timeout thread. - * The thread will wait the specified time, then will issue a - * SIGUSR2 signal that will interrupt the sem_wait() call. - * We pass the thread the id of the current thread, the delay, - * and the address of a flag to set on a timeout, so we can - * distinguish an interrupt caused by the timeout thread from - * one caused by some other signal. - */ - - volatile short timedOut; /* Flag to set on timeout */ - timeoutDetails details; /* All the stuff the thread must know */ - struct sigaction oldSignalAction; /* Current signal setting */ - pthread_t timeoutThread; /* Id of timeout thread */ - cleanupDetails cleaningDetails; /* What the cleanup routine needs */ - int oldCancelState; /* Previous cancellation state */ - int ignoreCancelState; /* Used in call, but ignored */ - int createStatus; /* Status of pthread_create() call */ - - /* If the current thread is cancelled (and CML does do this) - * we don't want to leave our timer thread running - if we've - * started the thread we want to make sure we join it in order - * to release its resources. So we set a cleanup handler to - * do this. We pass it the address of the structure that will - * hold all it needs to know. While we set all this up, - * we prevent ourselves being cancelled, so all this data is - * coherent. - */ - - pthread_setcancelstate (PTHREAD_CANCEL_DISABLE,&oldCancelState); - timeoutThread = (pthread_t) 0; - cleaningDetails.timedOutShort = &timedOut; - cleaningDetails.threadIdAddr = &timeoutThread; - cleaningDetails.sigHandlerAddr = &oldSignalAction; - pthread_cleanup_push (timeoutThreadCleanup,&cleaningDetails); - - /* Set up the details for the thread. Clear the timeout flag, - * record the current SIGUSR2 action settings so we can restore - * them later. - */ - - details.delay.tv_sec = secsToWait; - details.delay.tv_nsec = nsecsToWait; - details.callingThread = pthread_self(); - details.timedOutShort = &timedOut; - timedOut = FALSE; - sigaction (SIGUSR2,NULL,&oldSignalAction); - - /* Start up the timeout thread. Once we've done that, we can - * restore the previous cancellation state. - */ - - createStatus = pthread_create(&timeoutThread,NULL, - timeoutThreadMain, (void*)&details); - pthread_setcancelstate (oldCancelState,&ignoreCancelState); - - if (createStatus < 0) { - - /* Failed to create thread. errno will already be set properly */ - - result = -1; - - } else { - - /* Thread created OK. This is where we wait for the semaphore. - */ - - if (sem_wait(sem) == 0) { - - /* Got the semaphore OK. We return zero, and all's well. */ - - result = 0; - - } else { - - /* If we got a -1 error from sem_wait(), it may be because - * it was interrupted by a timeout, or failed for some - * other reason. We check for the expected timeout - * condition, which is an 'interrupted' status and the - * timeout flag set by the timeout thread. We report that as - * a timeout error. Anything else is some other error and - * errno is already set properly. - */ - - result = -1; - if (errno == EINTR) { - if (timedOut) errno = ETIMEDOUT; - } - } - - } - - /* The cleanup routine - timeoutThreadCleanup() - packages up - * any tidying up that is needed, including joining with the - * timer thread. This will be called if the current thread is - * cancelled, but we need it to happen anyway, so we set the - * execute flag true here as we remove it from the list of - * cleanup routines to be called. So normally, this line amounts - * to calling timeoutThreadCleanup(). - */ - - pthread_cleanup_pop (TRUE); - } - } - } - return (result); -} - -/* -------------------------------------------------------------------------- */ -/* - * t i m e o u t T h r e a d C l e a n u p - * - * This internal routine tidies up at the end of a sem_timedwait() call. - * It is set as a cleanup routine for the current thread (not the timer - * thread) so it is executed even if the thread is cancelled. This is - * important, as we need to tidy up the timeout thread. If we took the - * semaphore (in other words, if we didn't timeout) then the timer thread - * will still be running, sitting in its nanosleep() call, and we need - * to cancel it. If the timer thread did signal a timeout then it will - * now be closing down. In either case, we need to join it (using a call - * to pthread_join()) or its resources will never be released. - * The single argument is a pointer to a cleanupDetails structure that has - * all the routine needs to know. - */ - -static void timeoutThreadCleanup (void* passedPtr) -{ - /* Get what we need from the structure we've been passed. */ - - cleanupDetails *detailsPtr = (cleanupDetails*) passedPtr; - short timedOut = *(detailsPtr->timedOutShort); - pthread_t timeoutThread = *(detailsPtr->threadIdAddr); - - /* If we created the thread, stop it - doesn't matter if it's no longer - * running, pthread_cancel can handle that. We make sure we wait for it - * to complete, because it is this pthread_join() call that releases any - * memory the thread may have allocated. Note that cancelling a thread is - * generally not a good idea, because of the difficulty of cleaning up - * after it, but this is a very simple thread that does nothing but call - * nanosleep(), and that we can cancel quite happily. - */ - - if (!timedOut) pthread_cancel(timeoutThread); - pthread_join(timeoutThread,NULL); - - /* The code originally restored the old action handler, which generally - * was the default handler that caused the task to exit. Just occasionally, - * there seem to be cases where the signal is still queued and ready to - * trigger even though the thread that presumably sent it off just before - * it was cancelled has finished. I had thought that once we'd joined - * that thread, we could be sure of not seeing the signal, but that seems - * not to be the case, and so restoring a handler that will allow the task - * to crash is not a good idea, and so the line below has been commented - * out. - * - * sigaction (SIGUSR2,detailsPtr->sigHandlerAddr,NULL); - */ -} - -/* -------------------------------------------------------------------------- */ -/* - * t i m e o u t T h r e a d M a i n - * - * This internal routine is the main code for the timeout thread. - * The single argument is a pointer to a timeoutDetails structure that has - * all the thread needs to know - thread to signal, delay time, and the - * address of a flag to set if it triggers a timeout. - */ - -static void* timeoutThreadMain (void* passedPtr) -{ - void* Return = (void*) 0; - - /* We grab all the data held in the calling thread right now. In some - * cases, we find that the calling thread has vanished and released - * its memory, including the details structure, by the time the timeout - * expires, and then we get an access violation when we try to set the - * 'timed out' flag. - */ - - timeoutDetails details = *((timeoutDetails*) passedPtr); - struct timespec requestedDelay = details.delay; - - /* We do a nanosleep() for the specified delay, and then trigger a - * timeout. Note that we allow for the case where the nanosleep() is - * interrupted, and restart it for the remaining time. If the - * thread that is doing the sem_wait() call gets the semaphore, it - * will cancel this thread, which is fine as we aren't doing anything - * other than a sleep and a signal. - */ - - for (;;) { - struct timespec remainingDelay; - if (nanosleep (&requestedDelay,&remainingDelay) == 0) { - break; - } else if (errno == EINTR) { - requestedDelay = remainingDelay; - } else { - Return = (void*) errno; - break; - } - } - - /* We've completed the delay without being cancelled, so we now trigger - * the timeout by sending a signal to the calling thread. And that's it, - * although we set the timeout flag first to indicate that it was us - * that interrupted the sem_wait() call. One precaution: before we - * try to set the timed-out flag, make sure the calling thread still - * exists - this may not be the case if things are closing down a bit - * messily. We check this quickly using a zero test signal. - */ - - if (pthread_kill(details.callingThread,0) == 0) { - *(details.timedOutShort) = TRUE; - if (triggerSignal (SIGUSR2,details.callingThread) < 0) { - Return = (void*) errno; - } - } - - return Return; -} - -/* -------------------------------------------------------------------------- */ -/* - * t r i g g e r S i g n a l - * - * This is a general purpose routine that sends a specified signal to - * a specified thread, setting up a signal handler that does nothing, - * and then giving the signal. The only effect will be to interrupt any - * operation that is currently blocking - in this case, we expect this to - * be a sem_wait() call. - */ - -static int triggerSignal (int Signal, pthread_t Thread) -{ - int Result = 0; - struct sigaction SignalDetails; - SignalDetails.sa_handler = ignoreSignal; - SignalDetails.sa_flags = 0; - (void) sigemptyset(&SignalDetails.sa_mask); - if ((Result = sigaction(Signal,&SignalDetails,NULL)) == 0) { - Result = pthread_kill(Thread,Signal); - } - return Result; -} - -/* -------------------------------------------------------------------------- */ -/* - * i g n o r e S i g n a l - * - * And this is the signal handler that does nothing. (It clears its argument, - * but this has no effect and prevents a compiler warning about an unused - * argument.) - */ - -static void ignoreSignal (int Signal) { - Signal = 0; -} - -#endif diff --git a/src/frontend/qt_sdl/sem_timedwait.h b/src/frontend/qt_sdl/sem_timedwait.h deleted file mode 100644 index 42ae201e..00000000 --- a/src/frontend/qt_sdl/sem_timedwait.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef __SEM_TIMEDWAIT_H -#define __SEM_TIMEDWAIT_H - -#ifdef __APPLE__ -int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout); -#endif - -#endif diff --git a/src/net/LAN.cpp b/src/net/LAN.cpp index ebc66fd8..8cd39584 100644 --- a/src/net/LAN.cpp +++ b/src/net/LAN.cpp @@ -653,6 +653,8 @@ void LAN::ProcessHostEvent(ENetEvent& event) enet_packet_destroy(event.packet); } break; + case ENET_EVENT_TYPE_NONE: + break; } } @@ -777,6 +779,8 @@ void LAN::ProcessClientEvent(ENetEvent& event) enet_packet_destroy(event.packet); } break; + case ENET_EVENT_TYPE_NONE: + break; } } diff --git a/src/net/Net_Slirp.cpp b/src/net/Net_Slirp.cpp index 0386c586..cdd1e553 100644 --- a/src/net/Net_Slirp.cpp +++ b/src/net/Net_Slirp.cpp @@ -54,7 +54,6 @@ const u8 kServerMAC[6] = {0x00, 0xAB, 0x33, 0x28, 0x99, 0x44}; // https://stackoverflow.com/questions/5404277/porting-clock-gettime-to-windows struct timespec { long tv_sec; long tv_nsec; }; -#define CLOCK_MONOTONIC 1312 int clock_gettime(int, struct timespec *spec) { diff --git a/src/net/Netplay.cpp b/src/net/Netplay.cpp index 1dc04282..c89dbf4e 100644 --- a/src/net/Netplay.cpp +++ b/src/net/Netplay.cpp @@ -726,6 +726,8 @@ void ProcessHost() } } break; + case ENET_EVENT_TYPE_NONE: + break; } } } @@ -822,6 +824,8 @@ printf("birf\n"); } } break; + case ENET_EVENT_TYPE_NONE: + break; } } }