diff --git a/Common/ConsoleListener.cpp b/Common/ConsoleListener.cpp index 0dfcf3914f..e5d3ef9c4c 100644 --- a/Common/ConsoleListener.cpp +++ b/Common/ConsoleListener.cpp @@ -101,7 +101,7 @@ void ConsoleListener::Open(bool Hidden, int Width, int Height, const char *Title if (hTriggerEvent != NULL && hThread == NULL) { logPending = new char[LOG_PENDING_MAX]; - hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) &ConsoleListener::RunThread, this, 0, NULL); + hThread = (HANDLE)_beginthreadex(NULL, 0, &ConsoleListener::RunThread, this, 0, NULL); } #endif } @@ -246,9 +246,9 @@ COORD ConsoleListener::GetCoordinates(int BytesRead, int BufferWidth) return Ret; } -DWORD WINAPI ConsoleListener::RunThread(LPVOID lpParam) +unsigned int WINAPI ConsoleListener::RunThread(void *lpParam) { - ConsoleListener *consoleLog = (ConsoleListener *) lpParam; + ConsoleListener *consoleLog = (ConsoleListener *)lpParam; consoleLog->LogWriterThread(); return 0; } diff --git a/Common/ConsoleListener.h b/Common/ConsoleListener.h index 42547c0a00..1eff61a358 100644 --- a/Common/ConsoleListener.h +++ b/Common/ConsoleListener.h @@ -50,7 +50,7 @@ private: HWND GetHwnd(void); HANDLE hConsole; - static DWORD WINAPI RunThread(LPVOID lpParam); + static unsigned int WINAPI RunThread(void *lpParam); void LogWriterThread(); void SendToThread(LogTypes::LOG_LEVELS Level, const char *Text); void WriteToConsole(LogTypes::LOG_LEVELS Level, const char *Text, size_t Len); diff --git a/Core/Core.cpp b/Core/Core.cpp index 951a0578fd..d1170cce73 100644 --- a/Core/Core.cpp +++ b/Core/Core.cpp @@ -70,6 +70,11 @@ bool Core_IsStepping() return coreState == CORE_STEPPING || coreState == CORE_POWERDOWN; } +bool Core_IsActive() +{ + return coreState == CORE_RUNNING || coreState == CORE_NEXTFRAME || coreStatePending; +} + bool Core_IsInactive() { return coreState != CORE_RUNNING && coreState != CORE_NEXTFRAME && !coreStatePending; @@ -77,7 +82,7 @@ bool Core_IsInactive() void Core_WaitInactive() { - while (!Core_IsInactive()) + while (Core_IsActive()) m_hInactiveEvent.wait(m_hInactiveMutex); } diff --git a/Core/Core.h b/Core/Core.h index 2994ca55fe..b26103b740 100644 --- a/Core/Core.h +++ b/Core/Core.h @@ -33,6 +33,7 @@ void Core_Halt(const char *msg); bool Core_IsStepping(); +bool Core_IsActive(); bool Core_IsInactive(); void Core_WaitInactive(); void Core_WaitInactive(int milliseconds); diff --git a/Core/System.cpp b/Core/System.cpp index dbafe42f57..d4d4e22d87 100644 --- a/Core/System.cpp +++ b/Core/System.cpp @@ -97,7 +97,8 @@ bool PSP_Init(const CoreParameter &coreParam, std::string *error_string) // TODO: Check Game INI here for settings, patches and cheats, and modify coreParameter accordingly std::string filename = coreParameter.fileToStart; - if (!LoadFile(filename, error_string)) { + if (!LoadFile(filename, error_string) || coreState == CORE_POWERDOWN) + { pspFileSystem.Shutdown(); CoreTiming::Shutdown(); __KernelShutdown(); diff --git a/Windows/DSoundStream.cpp b/Windows/DSoundStream.cpp index 88d2426c6f..45047172bf 100644 --- a/Windows/DSoundStream.cpp +++ b/Windows/DSoundStream.cpp @@ -110,7 +110,7 @@ namespace DSound int lastPos; short realtimeBuffer[BUFSIZE * 2]; - DWORD WINAPI soundThread(void *) + unsigned int WINAPI soundThread(void *) { currentPos = 0; lastPos = 0; @@ -175,8 +175,7 @@ namespace DSound memset(p1,0,num1); dsBuffer->Unlock(p1,num1,0,0); totalRenderedBytes = -bufferSize; - DWORD h; - hThread = CreateThread(0,0,soundThread,0,0,&h); + hThread = (HANDLE)_beginthreadex(0, 0, soundThread, 0, 0, 0); SetThreadPriority(hThread, THREAD_PRIORITY_ABOVE_NORMAL); return true; } diff --git a/Windows/Debugger/Debugger_Disasm.cpp b/Windows/Debugger/Debugger_Disasm.cpp index e0d11a8939..135a6af73a 100644 --- a/Windows/Debugger/Debugger_Disasm.cpp +++ b/Windows/Debugger/Debugger_Disasm.cpp @@ -228,7 +228,7 @@ BOOL CDisasm::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) case IDC_MEMCHECK: { - bool isRunning = !Core_IsInactive(); + bool isRunning = Core_IsActive(); if (isRunning) { SetDebugMode(true); diff --git a/Windows/EmuThread.cpp b/Windows/EmuThread.cpp index cfea3c8269..76ba989006 100644 --- a/Windows/EmuThread.cpp +++ b/Windows/EmuThread.cpp @@ -7,6 +7,8 @@ #include "StringUtils.h" #include "../Globals.h" #include "EmuThread.h" +#include "WndMainWindow.h" +#include "resource.h" #include "../Core/Reporting.h" #include "../Core/MemMap.h" #include "../Core/Core.h" @@ -17,34 +19,79 @@ #include #include +#include +#pragma intrinsic(_InterlockedExchange) +class EmuThreadLockGuard +{ +public: + EmuThreadLockGuard() { emuThreadCS_.Enter(); } + ~EmuThreadLockGuard() { emuThreadCS_.Leave(); } +private: + static struct EmuThreadCS + { + EmuThreadCS() { InitializeCriticalSection(&TheCS_); } + ~EmuThreadCS() { DeleteCriticalSection(&TheCS_); } + void Enter() { EnterCriticalSection(&TheCS_); } + void Leave() { LeaveCriticalSection(&TheCS_); } + CRITICAL_SECTION TheCS_; + } emuThreadCS_; +}; + +EmuThreadLockGuard::EmuThreadCS EmuThreadLockGuard::emuThreadCS_; static HANDLE emuThread; +static long emuThreadReady; + +enum EmuTreadStatus : long +{ + THREAD_NONE = 0, + THREAD_INIT, + THREAD_CORE_LOOP, + THREAD_SHUTDOWN, + THREAD_END, +}; HANDLE EmuThread_GetThreadHandle() { + EmuThreadLockGuard lock; return emuThread; } -DWORD TheThread(LPVOID x); +unsigned int WINAPI TheThread(void *); void EmuThread_Start() { - unsigned int i; - emuThread = (HANDLE)_beginthreadex(0,0,(unsigned int (__stdcall *)(void *))TheThread,(LPVOID)0,0,&i); + EmuThreadLockGuard lock; + emuThread = (HANDLE)_beginthreadex(0, 0, &TheThread, 0, 0, 0); } void EmuThread_Stop() { // DSound_UpdateSound(); Core_Stop(); - if (WAIT_TIMEOUT == WaitForSingleObject(EmuThread_GetThreadHandle(),300)) + Core_WaitInactive(800); + if (WAIT_TIMEOUT == WaitForSingleObject(emuThread, 800)) { - //MessageBox(0,"Wait for emuthread timed out, please alert the developer to possible deadlock or infinite loop in emuthread :(.",0,0); + MessageBox(MainWindow::GetHWND(),"Wait for emuthread timed out! :(\n" + "please alert the developer to possible deadlock or infinite loop in emuthread!", 0, 0); + } + { + EmuThreadLockGuard lock; + CloseHandle(emuThread); + emuThread = 0; } host->UpdateUI(); } -DWORD TheThread(LPVOID x) { +bool EmuThread_Ready() +{ + return emuThreadReady == THREAD_CORE_LOOP; +} + +unsigned int WINAPI TheThread(void *) +{ + _InterlockedExchange(&emuThreadReady, THREAD_INIT); + setCurrentThreadName("EmuThread"); std::string memstick, flash0; @@ -75,20 +122,36 @@ DWORD TheThread(LPVOID x) { INFO_LOG(BOOT, "Done."); _dbg_update_(); + if (coreState == CORE_POWERDOWN) { + INFO_LOG(BOOT, "Exit before core loop."); + goto shutdown; + } + + _InterlockedExchange(&emuThreadReady, THREAD_CORE_LOOP); + + if (g_Config.bBrowse) + { + PostMessage(MainWindow::GetHWND(), WM_COMMAND, ID_FILE_LOAD, 0); + //MainWindow::BrowseAndBoot(""); + } + Core_EnableStepping(FALSE); + Core_Run(); shutdown: + _InterlockedExchange(&emuThreadReady, THREAD_SHUTDOWN); + host = nativeHost; NativeShutdownGraphics(); NativeShutdown(); host = oldHost; - host->ShutdownGL(); + _InterlockedExchange(&emuThreadReady, THREAD_END); + //The CPU should return when a game is stopped and cleanup should be done here, //so we can restart the plugins (or load new ones) for the next game - _endthreadex(0); return 0; } diff --git a/Windows/EmuThread.h b/Windows/EmuThread.h index eedf558c40..ed1a9df08d 100644 --- a/Windows/EmuThread.h +++ b/Windows/EmuThread.h @@ -1,4 +1,22 @@ +// Copyright (c) 2013- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + #pragma once void EmuThread_Start(); -void EmuThread_Stop(); \ No newline at end of file +void EmuThread_Stop(); +bool EmuThread_Ready(); diff --git a/Windows/WndMainWindow.cpp b/Windows/WndMainWindow.cpp index cedfca8d7d..7f9ec35605 100644 --- a/Windows/WndMainWindow.cpp +++ b/Windows/WndMainWindow.cpp @@ -214,18 +214,21 @@ namespace MainWindow if (zoom < 1) zoom = 1; if (zoom > 4) zoom = 4; - RECT rc,rcOrig; + RECT rc, rcOrig; GetWindowRectAtZoom(zoom, rcOrig, rc); u32 style = WS_OVERLAPPEDWINDOW; hwndMain = CreateWindowEx(0,szWindowClass, "", style, - rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, NULL, NULL, hInstance, NULL); - SetTimer(hwndMain, TIMER_CURSORUPDATE, CURSORUPDATE_INTERVAL_MS, 0); - SetPlaying(0); + rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, NULL, NULL, hInstance, NULL); if (!hwndMain) return FALSE; + hwndDisplay = CreateWindowEx(0, szDisplayClass, TEXT(""), WS_CHILD | WS_VISIBLE, + rcOrig.left, rcOrig.top, rcOrig.right - rcOrig.left, rcOrig.bottom - rcOrig.top, hwndMain, 0, hInstance, 0); + if (!hwndDisplay) + return FALSE; + menu = GetMenu(hwndMain); #ifdef FINAL RemoveMenu(menu,2,MF_BYPOSITION); @@ -241,20 +244,22 @@ namespace MainWindow { SetMenuInfo(GetSubMenu(menu,i),&info); } + UpdateMenus(); - hwndDisplay = CreateWindowEx(0,szDisplayClass,TEXT(""), - WS_CHILD|WS_VISIBLE, - 0,0,/*rcOrig.left,rcOrig.top,*/rcOrig.right-rcOrig.left,rcOrig.bottom-rcOrig.top,hwndMain,0,hInstance,0); - - ShowWindow(hwndMain, nCmdShow); //accept dragged files DragAcceptFiles(hwndMain, TRUE); + SetTimer(hwndMain, TIMER_CURSORUPDATE, CURSORUPDATE_INTERVAL_MS, 0); + + Update(); + SetPlaying(0); + + ShowWindow(hwndMain, nCmdShow); + #if ENABLE_TOUCH RegisterTouchWindow(hwndDisplay, TWF_WANTPALM); #endif - SetFocus(hwndMain); SetFocus(hwndDisplay); return TRUE; @@ -429,6 +434,8 @@ namespace MainWindow case WM_COMMAND: { + if (!EmuThread_Ready()) + return DefWindowProc(hWnd, message, wParam, lParam); I18NCategory *g = GetI18NCategory("Graphics"); wmId = LOWORD(wParam); @@ -735,6 +742,9 @@ namespace MainWindow case WM_DROPFILES: { + if (!EmuThread_Ready()) + return DefWindowProc(hWnd, message, wParam, lParam); + HDROP hdrop = (HDROP)wParam; int count = DragQueryFile(hdrop,0xFFFFFFFF,0,0); if (count != 1) @@ -760,21 +770,14 @@ namespace MainWindow break; case WM_CLOSE: - Core_Stop(); - Core_WaitInactive(200); + /* + if (g_Config.bConfirmOnQuit && __KernelIsRunning()) + if (IDYES != MessageBox(hwndMain, "A game is in progress. Are you sure you want to exit?", + "Are you sure?", MB_YESNO | MB_ICONQUESTION)) + return 0; + //*/ EmuThread_Stop(); - /* - if (g_Config.bConfirmOnQuit && CCore::IsRunning()) - { - if (IDNO==MessageBox(hwndMain,"A game is in progress. Are you sure you want to exit?","Are you sure?",MB_YESNO|MB_ICONQUESTION)) - return 1;//or 1? - else - return DefWindowProc(hWnd,message,wParam,lParam); - break; - } - else - */ return DefWindowProc(hWnd,message,wParam,lParam); case WM_DESTROY: diff --git a/Windows/main.cpp b/Windows/main.cpp index 280520f9e4..719062c8f4 100644 --- a/Windows/main.cpp +++ b/Windows/main.cpp @@ -64,9 +64,11 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin hideLog = false; #endif + LogManager::Init(); + LogManager::GetInstance()->GetConsoleListener()->Open(hideLog, 150, 120, "PPSSPP Debug Console"); + LogManager::GetInstance()->SetLogLevel(LogTypes::G3D, LogTypes::LERROR); + g_Config.Load(); - VFSRegister("", new DirectoryAssetReader("assets/")); - VFSRegister("", new DirectoryAssetReader("")); // The rest is handled in NativeInit(). for (int i = 1; i < __argc; ++i) @@ -89,6 +91,9 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin } } + VFSRegister("", new DirectoryAssetReader("assets/")); + VFSRegister("", new DirectoryAssetReader("")); + //Windows, API init stuff INITCOMMONCONTROLSEX comm; comm.dwSize = sizeof(comm); @@ -97,15 +102,13 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin timeBeginPeriod(1); MainWindow::Init(_hInstance); - HACCEL hAccelTable = LoadAccelerators(_hInstance, (LPCTSTR)IDR_ACCELS); g_hPopupMenus = LoadMenu(_hInstance, (LPCSTR)IDR_POPUPMENUS); MainWindow::Show(_hInstance, iCmdShow); - host = new WindowsHost(MainWindow::GetHWND(), MainWindow::GetDisplayHWND()); HWND hwndMain = MainWindow::GetHWND(); - HMENU menu = GetMenu(hwndMain); - + HWND hwndDisplay = MainWindow::GetDisplayHWND(); + //initialize custom controls CtrlDisAsmView::init(); CtrlMemView::init(); @@ -114,25 +117,15 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin DialogManager::AddDlg(memoryWindow[0] = new CMemoryDlg(_hInstance, hwndMain, currentDebugMIPS)); DialogManager::AddDlg(vfpudlg = new CVFPUDlg(_hInstance, hwndMain, currentDebugMIPS)); - MainWindow::Update(); - MainWindow::UpdateMenus(); - - LogManager::Init(); - LogManager::GetInstance()->GetConsoleListener()->Open(hideLog, 150, 120, "PPSSPP Debug Console"); - LogManager::GetInstance()->SetLogLevel(LogTypes::G3D, LogTypes::LERROR); + host = new WindowsHost(hwndMain, hwndDisplay); // Emu thread is always running! EmuThread_Start(); - if (g_Config.bBrowse) - MainWindow::BrowseAndBoot(""); - - if (!hideLog) - SetForegroundWindow(hwndMain); + HACCEL hAccelTable = LoadAccelerators(_hInstance, (LPCTSTR)IDR_ACCELS); //so.. we're at the message pump of the GUI thread - MSG msg; - while (GetMessage(&msg, NULL, 0, 0)) //while no quit + for (MSG msg; GetMessage(&msg, NULL, 0, 0); ) // for no quit { //DSound_UpdateSound();