Wiimote: Fixed the hanging for real. Any call to a function in the wxDialog frame class while the main thread is in a WaitForSingleObject() loop or any other loop will hang the g_pReadThread execution until sometime after that loop has ended. So we must wait for pReadThread to stop from the wxDialog with a timer, we can not use any loop in the main thread to wait for it to stop.

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@2083 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
John Peterson 2009-02-03 07:43:52 +00:00
parent f999ae94df
commit 5972f886ab
6 changed files with 63 additions and 35 deletions

View File

@ -91,6 +91,7 @@ BEGIN_EVENT_TABLE(ConfigDialog,wxDialog)
EVT_BUTTON(IDB_RECORD + 15, ConfigDialog::RecordMovement) EVT_BUTTON(IDB_RECORD + 15, ConfigDialog::RecordMovement)
EVT_TIMER(IDTM_UPDATE, ConfigDialog::Update) EVT_TIMER(IDTM_UPDATE, ConfigDialog::Update)
EVT_TIMER(IDTM_SHUTDOWN, ConfigDialog::ShutDown)
END_EVENT_TABLE() END_EVENT_TABLE()
///////////////////////////// /////////////////////////////
@ -104,6 +105,7 @@ ConfigDialog::ConfigDialog(wxWindow *parent, wxWindowID id, const wxString &titl
{ {
#if wxUSE_TIMER #if wxUSE_TIMER
m_TimeoutTimer = new wxTimer(this, IDTM_UPDATE); m_TimeoutTimer = new wxTimer(this, IDTM_UPDATE);
m_ShutDownTimer = new wxTimer(this, IDTM_SHUTDOWN);
m_TimeoutATimer = new wxTimer(this, IDTM_UPDATEA); m_TimeoutATimer = new wxTimer(this, IDTM_UPDATEA);
// Reset values // Reset values
m_bWaitForRecording = false; m_bWaitForRecording = false;
@ -139,23 +141,37 @@ void ConfigDialog::OnKeyDown(wxKeyEvent& event)
UpdateGUI(); UpdateGUI();
} }
} }
void ConfigDialog::OnClose(wxCloseEvent& WXUNUSED (event)) void ConfigDialog::OnClose(wxCloseEvent& WXUNUSED (event))
{ {
g_FrameOpen = false;
SaveFile(); SaveFile();
g_Config.Save(); g_Config.Save();
g_FrameOpen = false;
//SuccessAlert("Saved\n"); //SuccessAlert("Saved\n");
if (!g_EmulatorRunning) Shutdown(); if (!g_EmulatorRunning) Shutdown();
EndModal(0); EndModal(0);
} }
/* Timeout the shutdown. In Windows at least the g_pReadThread execution will hang at any attempt to
call a frame function after the main thread has entered WaitForSingleObject() or any other loop.
We must therefore shut down the thread from here and wait for that before we can call ShutDown(). */
void ConfigDialog::ShutDown(wxTimerEvent& WXUNUSED(event))
{
// Close() is a wxWidgets function that will trigger EVT_CLOSE() and then call this->Destroy().
if(!WiiMoteReal::g_ThreadGoing)
{
m_ShutDownTimer->Stop();
Close();
}
}
void ConfigDialog::CloseClick(wxCommandEvent& event) void ConfigDialog::CloseClick(wxCommandEvent& event)
{ {
switch(event.GetId()) switch(event.GetId())
{ {
case ID_CLOSE: case ID_CLOSE:
// wxWidgets function. This will also trigger EVT_CLOSE(). WiiMoteReal::g_Shutdown = true;
Close(); m_ShutDownTimer->Start(10);
break; break;
case ID_APPLY: case ID_APPLY:
SaveFile(); SaveFile();

View File

@ -60,8 +60,9 @@ class ConfigDialog : public wxDialog
void DoRecordMovement(u8 _x, u8 _y, u8 _z, const u8 *_IR, int IRBytes); void DoRecordMovement(u8 _x, u8 _y, u8 _z, const u8 *_IR, int IRBytes);
void DoRecordA(bool Pressed); void DoRecordA(bool Pressed);
void ConvertToString(); void ConvertToString();
wxTimer *m_TimeoutTimer, *m_TimeoutATimer; wxTimer *m_TimeoutTimer, *m_ShutDownTimer, *m_TimeoutATimer;
void Update(wxTimerEvent& WXUNUSED(event)); void Update(wxTimerEvent& WXUNUSED(event));
void ShutDown(wxTimerEvent& WXUNUSED(event));
void UpdateA(wxTimerEvent& WXUNUSED(event)); void UpdateA(wxTimerEvent& WXUNUSED(event));
private: private:
@ -105,7 +106,7 @@ class ConfigDialog : public wxDialog
ID_CLOSE = 1000, ID_CLOSE = 1000,
ID_APPLY, ID_APPLY,
ID_ABOUTOGL, ID_ABOUTOGL,
IDTM_EXIT, IDTM_UPDATE, IDTM_UPDATEA, // Timer IDTM_EXIT, IDTM_UPDATE, IDTM_SHUTDOWN, IDTM_UPDATEA, // Timer
ID_NOTEBOOK, ID_NOTEBOOK,
ID_PAGEEMU, ID_PAGEEMU,

View File

@ -20,13 +20,13 @@
// Includes // Includes
// ¯¯¯¯¯¯¯¯¯¯ // ¯¯¯¯¯¯¯¯¯¯
#include <iostream> // System #include <iostream> // System
#include "pluginspecs_wiimote.h"
#include "wiiuse.h" // Externals #include "wiiuse.h" // Externals
#include "ConsoleWindow.h" // Common #include "ConsoleWindow.h" // Common
#include "StringUtil.h" #include "StringUtil.h"
#include "Timer.h" #include "Timer.h"
#include "pluginspecs_wiimote.h"
#include "wiimote_real.h" // Local #include "wiimote_real.h" // Local
#include "wiimote_hid.h" #include "wiimote_hid.h"
@ -44,13 +44,13 @@ namespace WiiMoteReal
void handle_ctrl_status(struct wiimote_t* wm) void handle_ctrl_status(struct wiimote_t* wm)
{ {
printf("\n\n--- CONTROLLER STATUS [wiimote id %i] ---\n", wm->unid); Console::Print("\n\n--- CONTROLLER STATUS [wiimote id %i] ---\n", wm->unid);
printf("attachment: %i\n", wm->exp.type); Console::Print("attachment: %i\n", wm->exp.type);
printf("speaker: %i\n", WIIUSE_USING_SPEAKER(wm)); Console::Print("speaker: %i\n", WIIUSE_USING_SPEAKER(wm));
printf("ir: %i\n", WIIUSE_USING_IR(wm)); Console::Print("ir: %i\n", WIIUSE_USING_IR(wm));
printf("leds: %i %i %i %i\n", WIIUSE_IS_LED_SET(wm, 1), WIIUSE_IS_LED_SET(wm, 2), WIIUSE_IS_LED_SET(wm, 3), WIIUSE_IS_LED_SET(wm, 4)); Console::Print("leds: %i %i %i %i\n", WIIUSE_IS_LED_SET(wm, 1), WIIUSE_IS_LED_SET(wm, 2), WIIUSE_IS_LED_SET(wm, 3), WIIUSE_IS_LED_SET(wm, 4));
printf("battery: %f %%\n", wm->battery_level); Console::Print("battery: %f %%\n", wm->battery_level);
} }
@ -73,7 +73,7 @@ bool IRDataOK(struct wiimote_t* wm)
void handle_event(struct wiimote_t* wm) void handle_event(struct wiimote_t* wm)
{ {
printf("\n\n--- EVENT [id %i] ---\n", wm->unid); //Console::Print("\n\n--- EVENT [id %i] ---\n", wm->unid);
/* if a button is pressed, report it */ /* if a button is pressed, report it */
if (IS_PRESSED(wm, WIIMOTE_BUTTON_A)) Console::Print("A pressed\n"); if (IS_PRESSED(wm, WIIMOTE_BUTTON_A)) Console::Print("A pressed\n");
@ -111,9 +111,8 @@ void handle_event(struct wiimote_t* wm)
wiiuse_set_ir(wm, 1); wiiuse_set_ir(wm, 1);
/* Print battery status */ /* Print battery status */
if(frame) if(frame && g_Config.bUpdateRealWiimote)
if(g_Config.bUpdateRealWiimote) frame->m_GaugeBattery->SetValue((int)floor((wm->battery_level * 100) + 0.5));
frame->m_GaugeBattery->SetValue((int)floor((wm->battery_level * 100) + 0.5));
/* If the accelerometer is turned on then print angles */ /* If the accelerometer is turned on then print angles */
if (WIIUSE_USING_ACC(wm) && WIIUSE_USING_IR(wm)) if (WIIUSE_USING_ACC(wm) && WIIUSE_USING_IR(wm))
@ -211,9 +210,15 @@ void handle_event(struct wiimote_t* wm)
void ReadWiimote() void ReadWiimote()
{ {
/* I place this outside wiiuse_poll() to produce a continous recording regardless of the status
change of the Wiimote, wiiuse_poll() is only true if the status has changed. However, this the
timing functions for recording playback that checks the time of the recording this should not
be needed. But I still use it becase it seemed like state_changed() or the threshold values or
something else might fail so that only huge status changed were reported. */
handle_event(g_WiiMotesFromWiiUse[0]); handle_event(g_WiiMotesFromWiiUse[0]);
std::string Temp; std::string Temp;
// Read formatted data
// Read formatted Wiimote data
if (wiiuse_poll(g_WiiMotesFromWiiUse, MAX_WIIMOTES)) if (wiiuse_poll(g_WiiMotesFromWiiUse, MAX_WIIMOTES))
{ {
/* /*
@ -297,4 +302,7 @@ void ReadWiimote()
} }
} }
}; // end of namespace }; // end of namespace

View File

@ -76,7 +76,7 @@ HINSTANCE g_hInstance;
#if defined(HAVE_WX) && HAVE_WX #if defined(HAVE_WX) && HAVE_WX
wxWindow win; wxWindow win;
ConfigDialog *frame; ConfigDialog *frame = NULL;
class wxDLLApp : public wxApp class wxDLLApp : public wxApp
{ {
@ -159,11 +159,12 @@ void DllConfig(HWND _hParent)
//Console::Open(); //Console::Open();
DoInitialize(); DoInitialize();
g_FrameOpen = true;
frame = new ConfigDialog(&win); frame = new ConfigDialog(&win);
g_FrameOpen = true;
frame->ShowModal(); /* We don't need to use ShowModal() anymore becaue FreeLibrary() is not called after this function
//frame.Show(); anymore */
//frame->ShowModal();
frame->Show();
#ifdef _WIN32 #ifdef _WIN32
win.SetHWND(0); win.SetHWND(0);
@ -200,7 +201,8 @@ extern "C" void Shutdown(void)
if(frame) frame->UpdateGUI(); if(frame) frame->UpdateGUI();
#endif #endif
// Don't shut down the wiimote when we still have the window open /* Don't shut down the wiimote when we still have the config window open, we may still want
want to use the Wiimote in the config window. */
return; return;
} }

View File

@ -69,6 +69,7 @@ Common::Thread* g_pReadThread = NULL;
int g_NumberOfWiiMotes; int g_NumberOfWiiMotes;
CWiiMote* g_WiiMotes[MAX_WIIMOTES]; CWiiMote* g_WiiMotes[MAX_WIIMOTES];
bool g_Shutdown = false; bool g_Shutdown = false;
bool g_ThreadGoing = false;
bool g_LocalThread = true; bool g_LocalThread = true;
bool g_IRSensing = false; bool g_IRSensing = false;
bool g_MotionSensing = false; bool g_MotionSensing = false;
@ -483,16 +484,11 @@ void Shutdown(void)
// Stop the loop in the thread // Stop the loop in the thread
g_Shutdown = true; g_Shutdown = true;
// Sleep this thread to wait for activity in g_pReadThread to stop entirely
Sleep(100);
// Stop the thread // Stop the thread
if (g_pReadThread != NULL) if (g_pReadThread != NULL)
{ {
// This sometimes hangs for some reason so I'm trying to disable it g_pReadThread->WaitForDeath();
// It seemed to hang in WaitForSingleObject(), but I don't know why delete g_pReadThread;
//g_pReadThread->WaitForDeath();
delete g_pReadThread;
g_pReadThread = NULL; g_pReadThread = NULL;
} }
@ -555,10 +551,13 @@ void Update()
{ {
while (!g_Shutdown) while (!g_Shutdown)
{ {
// We need g_ThreadGoing to do a manual WaitForSingleObject() from the configuration window
g_ThreadGoing = true;
if(g_Config.bUseRealWiimote && !g_RunTemporary) if(g_Config.bUseRealWiimote && !g_RunTemporary)
for (int i = 0; i < g_NumberOfWiiMotes; i++) g_WiiMotes[i]->ReadData(); for (int i = 0; i < g_NumberOfWiiMotes; i++) g_WiiMotes[i]->ReadData();
else else
ReadWiimote(); ReadWiimote();
g_ThreadGoing = false;
} }
return 0; return 0;
} }

View File

@ -46,6 +46,8 @@ void ReadWiimote();
#ifndef EXCLUDE_H #ifndef EXCLUDE_H
extern wiimote_t** g_WiiMotesFromWiiUse; extern wiimote_t** g_WiiMotesFromWiiUse;
extern bool g_Shutdown;
extern bool g_ThreadGoing;
extern int g_NumberOfWiiMotes; extern int g_NumberOfWiiMotes;
extern bool g_MotionSensing; extern bool g_MotionSensing;
extern bool g_IRSensing; extern bool g_IRSensing;