Replace balanced Core::PauseAndLock calls with RunAsCPUThread

Core::PauseAndLock requires all calls to it to be balanced, like this:

    const bool was_unpaused = Core::PauseAndLock(true);
    // do stuff on the CPU thread
    Core::PauseAndLock(false, was_unpaused);

Aside from being a bit cumbersome, it turns out all callers really
don't need to know about was_unpaused at all. They just need to do
something on the CPU thread safely, including locking/unlocking.

So this commit replaces Core::PauseAndLock with a function that
makes both the purpose and the scope of what is being run on the
CPU thread visually clear. This makes it harder to accidentally run
something on the wrong thread, or forget the second call to
PauseAndLock to unpause, or forget that it needs to be passed
was_unpaused at the end.

We also don't need comments to indicate code X is being run on the
CPU thread anymore, as the function name makes it obvious.
This commit is contained in:
Léo Lam 2017-07-21 14:06:02 +08:00
parent 2f0bec93cb
commit f106a9637d
13 changed files with 300 additions and 317 deletions

View File

@ -759,7 +759,7 @@ void RequestRefreshInfo()
s_request_refresh_info = true; s_request_refresh_info = true;
} }
bool PauseAndLock(bool do_lock, bool unpause_on_unlock) static bool PauseAndLock(bool do_lock, bool unpause_on_unlock)
{ {
// WARNING: PauseAndLock is not fully threadsafe so is only valid on the Host Thread // WARNING: PauseAndLock is not fully threadsafe so is only valid on the Host Thread
if (!IsRunning()) if (!IsRunning())
@ -806,6 +806,19 @@ bool PauseAndLock(bool do_lock, bool unpause_on_unlock)
return was_unpaused; return was_unpaused;
} }
void RunAsCPUThread(std::function<void()> function)
{
const bool is_cpu_thread = IsCPUThread();
bool was_unpaused = false;
if (!is_cpu_thread)
was_unpaused = PauseAndLock(true, true);
function();
if (!is_cpu_thread)
PauseAndLock(false, was_unpaused);
}
// Display FPS info // Display FPS info
// This should only be called from VI // This should only be called from VI
void VideoThrottle() void VideoThrottle()
@ -955,22 +968,20 @@ void UpdateWantDeterminism(bool initial)
{ {
NOTICE_LOG(COMMON, "Want determinism <- %s", new_want_determinism ? "true" : "false"); NOTICE_LOG(COMMON, "Want determinism <- %s", new_want_determinism ? "true" : "false");
bool was_unpaused = Core::PauseAndLock(true); RunAsCPUThread([&] {
s_wants_determinism = new_want_determinism;
const auto ios = IOS::HLE::GetIOS();
if (ios)
ios->UpdateWantDeterminism(new_want_determinism);
Fifo::UpdateWantDeterminism(new_want_determinism);
// We need to clear the cache because some parts of the JIT depend on want_determinism,
// e.g. use of FMA.
JitInterface::ClearCache();
s_wants_determinism = new_want_determinism; // Don't call InitializeWiiRoot during boot, because IOS already does it.
const auto ios = IOS::HLE::GetIOS(); if (!initial)
if (ios) Core::InitializeWiiRoot(s_wants_determinism);
ios->UpdateWantDeterminism(new_want_determinism); });
Fifo::UpdateWantDeterminism(new_want_determinism);
// We need to clear the cache because some parts of the JIT depend on want_determinism, e.g. use
// of FMA.
JitInterface::ClearCache();
// Don't call InitializeWiiRoot during boot, because IOS already does it.
if (!initial)
Core::InitializeWiiRoot(s_wants_determinism);
Core::PauseAndLock(false, was_unpaused);
} }
} }

View File

@ -74,12 +74,14 @@ void RequestRefreshInfo();
void UpdateTitle(); void UpdateTitle();
// waits until all systems are paused and fully idle, and acquires a lock on that state. // Run a function as the CPU thread.
// or, if doLock is false, releases a lock on that state and optionally unpauses. //
// calls must be balanced (once with doLock true, then once with doLock false) but may be recursive. // If called from the Host thread, the CPU thread is paused and the current thread temporarily
// the return value of the first call should be passed in as the second argument of the second call. // becomes the CPU thread while running the function.
// [NOT THREADSAFE] Host only // If called from the CPU thread, the function will be run directly.
bool PauseAndLock(bool doLock, bool unpauseOnUnlock = true); //
// This should only be called from the CPU thread or the host thread.
void RunAsCPUThread(std::function<void()> function);
// for calling back into UI code without introducing a dependency on it in core // for calling back into UI code without introducing a dependency on it in core
using StoppedCallbackFunc = std::function<void()>; using StoppedCallbackFunc = std::function<void()>;

View File

@ -476,12 +476,7 @@ static void InsertDiscCallback(u64 userdata, s64 cyclesLate)
// Can only be called by the host thread // Can only be called by the host thread
void ChangeDiscAsHost(const std::string& new_path) void ChangeDiscAsHost(const std::string& new_path)
{ {
bool was_unpaused = Core::PauseAndLock(true); Core::RunAsCPUThread([&] { ChangeDiscAsCPU(new_path); });
// The host thread is now temporarily the CPU thread
ChangeDiscAsCPU(new_path);
Core::PauseAndLock(false, was_unpaused);
} }
// Can only be called by the CPU thread // Can only be called by the CPU thread

View File

@ -544,68 +544,66 @@ bool BeginRecordingInput(int controllers)
if (s_playMode != MODE_NONE || controllers == 0) if (s_playMode != MODE_NONE || controllers == 0)
return false; return false;
bool was_unpaused = Core::PauseAndLock(true); Core::RunAsCPUThread([controllers] {
s_controllers = controllers;
s_currentFrame = s_totalFrames = 0;
s_currentLagCount = s_totalLagCount = 0;
s_currentInputCount = s_totalInputCount = 0;
s_totalTickCount = s_tickCountAtLastInput = 0;
s_bongos = 0;
s_memcards = 0;
if (NetPlay::IsNetPlayRunning())
{
s_bNetPlay = true;
s_recordingStartTime = ExpansionInterface::CEXIIPL::NetPlay_GetEmulatedTime();
}
else if (SConfig::GetInstance().bEnableCustomRTC)
{
s_recordingStartTime = SConfig::GetInstance().m_customRTCValue;
}
else
{
s_recordingStartTime = Common::Timer::GetLocalTimeSinceJan1970();
}
s_controllers = controllers; s_rerecords = 0;
s_currentFrame = s_totalFrames = 0;
s_currentLagCount = s_totalLagCount = 0;
s_currentInputCount = s_totalInputCount = 0;
s_totalTickCount = s_tickCountAtLastInput = 0;
s_bongos = 0;
s_memcards = 0;
if (NetPlay::IsNetPlayRunning())
{
s_bNetPlay = true;
s_recordingStartTime = ExpansionInterface::CEXIIPL::NetPlay_GetEmulatedTime();
}
else if (SConfig::GetInstance().bEnableCustomRTC)
{
s_recordingStartTime = SConfig::GetInstance().m_customRTCValue;
}
else
{
s_recordingStartTime = Common::Timer::GetLocalTimeSinceJan1970();
}
s_rerecords = 0; for (int i = 0; i < SerialInterface::MAX_SI_CHANNELS; ++i)
{
if (SConfig::GetInstance().m_SIDevice[i] == SerialInterface::SIDEVICE_GC_TARUKONGA)
s_bongos |= (1 << i);
}
for (int i = 0; i < SerialInterface::MAX_SI_CHANNELS; ++i) if (Core::IsRunningAndStarted())
{ {
if (SConfig::GetInstance().m_SIDevice[i] == SerialInterface::SIDEVICE_GC_TARUKONGA) const std::string save_path = File::GetUserPath(D_STATESAVES_IDX) + "dtm.sav";
s_bongos |= (1 << i); if (File::Exists(save_path))
} File::Delete(save_path);
if (Core::IsRunningAndStarted()) State::SaveAs(save_path);
{ s_bRecordingFromSaveState = true;
const std::string save_path = File::GetUserPath(D_STATESAVES_IDX) + "dtm.sav";
if (File::Exists(save_path))
File::Delete(save_path);
State::SaveAs(save_path); std::thread md5thread(GetMD5);
s_bRecordingFromSaveState = true; md5thread.detach();
GetSettings();
}
std::thread md5thread(GetMD5); // Wiimotes cause desync issues if they're not reset before launching the game
md5thread.detach(); if (!Core::IsRunningAndStarted())
GetSettings(); {
} // This will also reset the wiimotes for gamecube games, but that shouldn't do anything
Wiimote::ResetAllWiimotes();
}
// Wiimotes cause desync issues if they're not reset before launching the game s_playMode = MODE_RECORDING;
if (!Core::IsRunningAndStarted()) s_author = SConfig::GetInstance().m_strMovieAuthor;
{ s_temp_input.clear();
// This will also reset the wiimotes for gamecube games, but that shouldn't do anything
Wiimote::ResetAllWiimotes();
}
s_playMode = MODE_RECORDING; s_currentByte = 0;
s_author = SConfig::GetInstance().m_strMovieAuthor;
s_temp_input.clear();
s_currentByte = 0; if (Core::IsRunning())
Core::UpdateWantDeterminism();
if (Core::IsRunning()) });
Core::UpdateWantDeterminism();
Core::PauseAndLock(false, was_unpaused);
Core::DisplayMessage("Starting movie recording", 2000); Core::DisplayMessage("Starting movie recording", 2000);
return true; return true;

View File

@ -174,14 +174,14 @@ void MemChecks::Add(const TMemCheck& memory_check)
if (GetMemCheck(memory_check.start_address) == nullptr) if (GetMemCheck(memory_check.start_address) == nullptr)
{ {
bool had_any = HasAny(); bool had_any = HasAny();
bool lock = Core::PauseAndLock(true); Core::RunAsCPUThread([&] {
m_mem_checks.push_back(memory_check); m_mem_checks.push_back(memory_check);
// If this is the first one, clear the JIT cache so it can switch to // If this is the first one, clear the JIT cache so it can switch to
// watchpoint-compatible code. // watchpoint-compatible code.
if (!had_any && g_jit) if (!had_any && g_jit)
g_jit->ClearCache(); g_jit->ClearCache();
PowerPC::DBATUpdated(); PowerPC::DBATUpdated();
Core::PauseAndLock(false, lock); });
} }
} }
@ -191,12 +191,12 @@ void MemChecks::Remove(u32 address)
{ {
if (i->start_address == address) if (i->start_address == address)
{ {
bool lock = Core::PauseAndLock(true); Core::RunAsCPUThread([&] {
m_mem_checks.erase(i); m_mem_checks.erase(i);
if (!HasAny() && g_jit) if (!HasAny() && g_jit)
g_jit->ClearCache(); g_jit->ClearCache();
PowerPC::DBATUpdated(); PowerPC::DBATUpdated();
Core::PauseAndLock(false, lock); });
return; return;
} }
} }

View File

@ -207,42 +207,36 @@ void LoadFromBuffer(std::vector<u8>& buffer)
return; return;
} }
bool wasUnpaused = Core::PauseAndLock(true); Core::RunAsCPUThread([&] {
u8* ptr = &buffer[0];
u8* ptr = &buffer[0]; PointerWrap p(&ptr, PointerWrap::MODE_READ);
PointerWrap p(&ptr, PointerWrap::MODE_READ); DoState(p);
DoState(p); });
Core::PauseAndLock(false, wasUnpaused);
} }
void SaveToBuffer(std::vector<u8>& buffer) void SaveToBuffer(std::vector<u8>& buffer)
{ {
bool wasUnpaused = Core::PauseAndLock(true); Core::RunAsCPUThread([&] {
u8* ptr = nullptr;
PointerWrap p(&ptr, PointerWrap::MODE_MEASURE);
u8* ptr = nullptr; DoState(p);
PointerWrap p(&ptr, PointerWrap::MODE_MEASURE); const size_t buffer_size = reinterpret_cast<size_t>(ptr);
buffer.resize(buffer_size);
DoState(p); ptr = &buffer[0];
const size_t buffer_size = reinterpret_cast<size_t>(ptr); p.SetMode(PointerWrap::MODE_WRITE);
buffer.resize(buffer_size); DoState(p);
});
ptr = &buffer[0];
p.SetMode(PointerWrap::MODE_WRITE);
DoState(p);
Core::PauseAndLock(false, wasUnpaused);
} }
void VerifyBuffer(std::vector<u8>& buffer) void VerifyBuffer(std::vector<u8>& buffer)
{ {
bool wasUnpaused = Core::PauseAndLock(true); Core::RunAsCPUThread([&] {
u8* ptr = &buffer[0];
u8* ptr = &buffer[0]; PointerWrap p(&ptr, PointerWrap::MODE_VERIFY);
PointerWrap p(&ptr, PointerWrap::MODE_VERIFY); DoState(p);
DoState(p); });
Core::PauseAndLock(false, wasUnpaused);
} }
// return state number not in map // return state number not in map
@ -399,48 +393,44 @@ static void CompressAndDumpState(CompressAndDumpState_args save_args)
void SaveAs(const std::string& filename, bool wait) void SaveAs(const std::string& filename, bool wait)
{ {
// Pause the core while we save the state Core::RunAsCPUThread([&] {
bool wasUnpaused = Core::PauseAndLock(true); // Measure the size of the buffer.
u8* ptr = nullptr;
// Measure the size of the buffer. PointerWrap p(&ptr, PointerWrap::MODE_MEASURE);
u8* ptr = nullptr;
PointerWrap p(&ptr, PointerWrap::MODE_MEASURE);
DoState(p);
const size_t buffer_size = reinterpret_cast<size_t>(ptr);
// Then actually do the write.
{
std::lock_guard<std::mutex> lk(g_cs_current_buffer);
g_current_buffer.resize(buffer_size);
ptr = &g_current_buffer[0];
p.SetMode(PointerWrap::MODE_WRITE);
DoState(p); DoState(p);
} const size_t buffer_size = reinterpret_cast<size_t>(ptr);
if (p.GetMode() == PointerWrap::MODE_WRITE) // Then actually do the write.
{ {
Core::DisplayMessage("Saving State...", 1000); std::lock_guard<std::mutex> lk(g_cs_current_buffer);
g_current_buffer.resize(buffer_size);
ptr = &g_current_buffer[0];
p.SetMode(PointerWrap::MODE_WRITE);
DoState(p);
}
CompressAndDumpState_args save_args; if (p.GetMode() == PointerWrap::MODE_WRITE)
save_args.buffer_vector = &g_current_buffer; {
save_args.buffer_mutex = &g_cs_current_buffer; Core::DisplayMessage("Saving State...", 1000);
save_args.filename = filename;
save_args.wait = wait;
Flush(); CompressAndDumpState_args save_args;
g_save_thread = std::thread(CompressAndDumpState, save_args); save_args.buffer_vector = &g_current_buffer;
g_compressAndDumpStateSyncEvent.Wait(); save_args.buffer_mutex = &g_cs_current_buffer;
save_args.filename = filename;
save_args.wait = wait;
g_last_filename = filename; Flush();
} g_save_thread = std::thread(CompressAndDumpState, save_args);
else g_compressAndDumpStateSyncEvent.Wait();
{
// someone aborted the save by changing the mode?
Core::DisplayMessage("Unable to save: Internal DoState Error", 4000);
}
// Resume the core and disable stepping g_last_filename = filename;
Core::PauseAndLock(false, wasUnpaused); }
else
{
// someone aborted the save by changing the mode?
Core::DisplayMessage("Unable to save: Internal DoState Error", 4000);
}
});
} }
bool ReadHeader(const std::string& filename, StateHeader& header) bool ReadHeader(const std::string& filename, StateHeader& header)
@ -549,72 +539,68 @@ void LoadAs(const std::string& filename)
return; return;
} }
// Stop the core while we load the state Core::RunAsCPUThread([&] {
bool wasUnpaused = Core::PauseAndLock(true); g_loadDepth++;
g_loadDepth++; // Save temp buffer for undo load state
if (!Movie::IsJustStartingRecordingInputFromSaveState())
// Save temp buffer for undo load state
if (!Movie::IsJustStartingRecordingInputFromSaveState())
{
std::lock_guard<std::mutex> lk(g_cs_undo_load_buffer);
SaveToBuffer(g_undo_load_buffer);
if (Movie::IsMovieActive())
Movie::SaveRecording(File::GetUserPath(D_STATESAVES_IDX) + "undo.dtm");
else if (File::Exists(File::GetUserPath(D_STATESAVES_IDX) + "undo.dtm"))
File::Delete(File::GetUserPath(D_STATESAVES_IDX) + "undo.dtm");
}
bool loaded = false;
bool loadedSuccessfully = false;
std::string version_created_by;
// brackets here are so buffer gets freed ASAP
{
std::vector<u8> buffer;
LoadFileStateData(filename, buffer);
if (!buffer.empty())
{ {
u8* ptr = &buffer[0]; std::lock_guard<std::mutex> lk(g_cs_undo_load_buffer);
PointerWrap p(&ptr, PointerWrap::MODE_READ); SaveToBuffer(g_undo_load_buffer);
version_created_by = DoState(p); if (Movie::IsMovieActive())
loaded = true; Movie::SaveRecording(File::GetUserPath(D_STATESAVES_IDX) + "undo.dtm");
loadedSuccessfully = (p.GetMode() == PointerWrap::MODE_READ); else if (File::Exists(File::GetUserPath(D_STATESAVES_IDX) + "undo.dtm"))
File::Delete(File::GetUserPath(D_STATESAVES_IDX) + "undo.dtm");
} }
}
if (loaded) bool loaded = false;
{ bool loadedSuccessfully = false;
if (loadedSuccessfully) std::string version_created_by;
// brackets here are so buffer gets freed ASAP
{ {
Core::DisplayMessage(StringFromFormat("Loaded state from %s", filename.c_str()), 2000); std::vector<u8> buffer;
if (File::Exists(filename + ".dtm")) LoadFileStateData(filename, buffer);
Movie::LoadInput(filename + ".dtm");
else if (!Movie::IsJustStartingRecordingInputFromSaveState() && if (!buffer.empty())
!Movie::IsJustStartingPlayingInputFromSaveState()) {
Movie::EndPlayInput(false); u8* ptr = &buffer[0];
PointerWrap p(&ptr, PointerWrap::MODE_READ);
version_created_by = DoState(p);
loaded = true;
loadedSuccessfully = (p.GetMode() == PointerWrap::MODE_READ);
}
} }
else
if (loaded)
{ {
// failed to load if (loadedSuccessfully)
Core::DisplayMessage("Unable to load: Can't load state from other versions!", 4000); {
if (!version_created_by.empty()) Core::DisplayMessage(StringFromFormat("Loaded state from %s", filename.c_str()), 2000);
Core::DisplayMessage("The savestate was created using " + version_created_by, 4000); if (File::Exists(filename + ".dtm"))
Movie::LoadInput(filename + ".dtm");
else if (!Movie::IsJustStartingRecordingInputFromSaveState() &&
!Movie::IsJustStartingPlayingInputFromSaveState())
Movie::EndPlayInput(false);
}
else
{
// failed to load
Core::DisplayMessage("Unable to load: Can't load state from other versions!", 4000);
if (!version_created_by.empty())
Core::DisplayMessage("The savestate was created using " + version_created_by, 4000);
// since we could be in an inconsistent state now (and might crash or whatever), undo. // since we could be in an inconsistent state now (and might crash or whatever), undo.
if (g_loadDepth < 2) if (g_loadDepth < 2)
UndoLoadState(); UndoLoadState();
}
} }
}
if (s_on_after_load_callback) if (s_on_after_load_callback)
s_on_after_load_callback(); s_on_after_load_callback();
g_loadDepth--; g_loadDepth--;
});
// resume dat core
Core::PauseAndLock(false, wasUnpaused);
} }
void SetOnAfterLoadCallback(AfterLoadCallbackFunc callback) void SetOnAfterLoadCallback(AfterLoadCallbackFunc callback)
@ -624,24 +610,22 @@ void SetOnAfterLoadCallback(AfterLoadCallbackFunc callback)
void VerifyAt(const std::string& filename) void VerifyAt(const std::string& filename)
{ {
bool wasUnpaused = Core::PauseAndLock(true); Core::RunAsCPUThread([&] {
std::vector<u8> buffer;
LoadFileStateData(filename, buffer);
std::vector<u8> buffer; if (!buffer.empty())
LoadFileStateData(filename, buffer); {
u8* ptr = &buffer[0];
PointerWrap p(&ptr, PointerWrap::MODE_VERIFY);
DoState(p);
if (!buffer.empty()) if (p.GetMode() == PointerWrap::MODE_VERIFY)
{ Core::DisplayMessage(StringFromFormat("Verified state at %s", filename.c_str()), 2000);
u8* ptr = &buffer[0]; else
PointerWrap p(&ptr, PointerWrap::MODE_VERIFY); Core::DisplayMessage("Unable to Verify : Can't verify state from other revisions !", 4000);
DoState(p); }
});
if (p.GetMode() == PointerWrap::MODE_VERIFY)
Core::DisplayMessage(StringFromFormat("Verified state at %s", filename.c_str()), 2000);
else
Core::DisplayMessage("Unable to Verify : Can't verify state from other revisions !", 4000);
}
Core::PauseAndLock(false, wasUnpaused);
} }
void Init() void Init()

View File

@ -137,13 +137,13 @@ void Host_ConnectWiimote(int wm_idx, bool connect)
const auto ios = IOS::HLE::GetIOS(); const auto ios = IOS::HLE::GetIOS();
if (!ios || SConfig::GetInstance().m_bt_passthrough_enabled) if (!ios || SConfig::GetInstance().m_bt_passthrough_enabled)
return; return;
bool was_unpaused = Core::PauseAndLock(true); Core::RunAsCPUThread([&] {
const auto bt = std::static_pointer_cast<IOS::HLE::Device::BluetoothEmu>( const auto bt = std::static_pointer_cast<IOS::HLE::Device::BluetoothEmu>(
ios->GetDeviceByName("/dev/usb/oh1/57e/305")); ios->GetDeviceByName("/dev/usb/oh1/57e/305"));
if (bt) if (bt)
bt->AccessWiiMote(wm_idx | 0x100)->Activate(connect); bt->AccessWiiMote(wm_idx | 0x100)->Activate(connect);
Host_UpdateMainFrame(); Host_UpdateMainFrame();
Core::PauseAndLock(false, was_unpaused); });
}); });
} }

View File

@ -237,25 +237,24 @@ void IOWindow::UpdateDeviceList()
m_block.Set(true); m_block.Set(true);
m_devices_combo->clear(); m_devices_combo->clear();
const bool paused = Core::PauseAndLock(true); Core::RunAsCPUThread([&] {
g_controller_interface.RefreshDevices();
m_controller->UpdateReferences(g_controller_interface);
m_controller->UpdateDefaultDevice();
g_controller_interface.RefreshDevices(); // Adding default device regardless if it's currently connected or not
m_controller->UpdateReferences(g_controller_interface); const auto default_device = m_controller->default_device.ToString();
m_controller->UpdateDefaultDevice();
// Adding default device regardless if it's currently connected or not m_devices_combo->addItem(QString::fromStdString(default_device));
const auto default_device = m_controller->default_device.ToString();
m_devices_combo->addItem(QString::fromStdString(default_device)); for (const auto& name : g_controller_interface.GetAllDeviceStrings())
{
if (name != default_device)
m_devices_combo->addItem(QString::fromStdString(name));
}
for (const auto& name : g_controller_interface.GetAllDeviceStrings()) m_devices_combo->setCurrentIndex(0);
{ });
if (name != default_device)
m_devices_combo->addItem(QString::fromStdString(name));
}
m_devices_combo->setCurrentIndex(0);
Core::PauseAndLock(false, paused);
m_block.Set(false); m_block.Set(false);
} }

View File

@ -229,25 +229,23 @@ void MappingWindow::RefreshDevices()
{ {
m_devices_combo->clear(); m_devices_combo->clear();
const bool paused = Core::PauseAndLock(true); Core::RunAsCPUThread([&] {
g_controller_interface.RefreshDevices();
m_controller->UpdateReferences(g_controller_interface);
m_controller->UpdateDefaultDevice();
g_controller_interface.RefreshDevices(); const auto default_device = m_controller->default_device.ToString();
m_controller->UpdateReferences(g_controller_interface);
m_controller->UpdateDefaultDevice();
const auto default_device = m_controller->default_device.ToString(); m_devices_combo->addItem(QString::fromStdString(default_device));
m_devices_combo->addItem(QString::fromStdString(default_device)); for (const auto& name : g_controller_interface.GetAllDeviceStrings())
{
if (name != default_device)
m_devices_combo->addItem(QString::fromStdString(name));
}
for (const auto& name : g_controller_interface.GetAllDeviceStrings()) m_devices_combo->setCurrentIndex(0);
{ });
if (name != default_device)
m_devices_combo->addItem(QString::fromStdString(name));
}
m_devices_combo->setCurrentIndex(0);
Core::PauseAndLock(false, paused);
} }
void MappingWindow::ChangeMappingType(MappingWindow::Type type) void MappingWindow::ChangeMappingType(MappingWindow::Type type)

View File

@ -71,12 +71,12 @@ void GCAdapterConfigDiag::ScheduleAdapterUpdate()
void GCAdapterConfigDiag::OnUpdateAdapter(wxCommandEvent& WXUNUSED(event)) void GCAdapterConfigDiag::OnUpdateAdapter(wxCommandEvent& WXUNUSED(event))
{ {
bool unpause = Core::PauseAndLock(true); Core::RunAsCPUThread([this] {
if (GCAdapter::IsDetected()) if (GCAdapter::IsDetected())
m_adapter_status->SetLabelText(_("Adapter Detected")); m_adapter_status->SetLabelText(_("Adapter Detected"));
else else
m_adapter_status->SetLabelText(_("Adapter Not Detected")); m_adapter_status->SetLabelText(_("Adapter Not Detected"));
Core::PauseAndLock(false, unpause); });
} }
void GCAdapterConfigDiag::OnAdapterRumble(wxCommandEvent& event) void GCAdapterConfigDiag::OnAdapterRumble(wxCommandEvent& event)

View File

@ -1249,9 +1249,7 @@ void CFrame::DoExclusiveFullscreen(bool enable_fullscreen)
if (!g_renderer || g_renderer->IsFullscreen() == enable_fullscreen) if (!g_renderer || g_renderer->IsFullscreen() == enable_fullscreen)
return; return;
bool was_unpaused = Core::PauseAndLock(true); Core::RunAsCPUThread([enable_fullscreen] { g_renderer->SetFullscreen(enable_fullscreen); });
g_renderer->SetFullscreen(enable_fullscreen);
Core::PauseAndLock(false, was_unpaused);
} }
void CFrame::PollHotkeys(wxTimerEvent& event) void CFrame::PollHotkeys(wxTimerEvent& event)

View File

@ -1411,19 +1411,19 @@ void CFrame::ConnectWiimote(int wm_idx, bool connect)
if (Core::IsRunning() && SConfig::GetInstance().bWii && if (Core::IsRunning() && SConfig::GetInstance().bWii &&
!SConfig::GetInstance().m_bt_passthrough_enabled) !SConfig::GetInstance().m_bt_passthrough_enabled)
{ {
bool was_unpaused = Core::PauseAndLock(true); Core::RunAsCPUThread([&] {
const auto ios = IOS::HLE::GetIOS(); const auto ios = IOS::HLE::GetIOS();
if (!ios) if (!ios)
return; return;
const auto bt = std::static_pointer_cast<IOS::HLE::Device::BluetoothEmu>( const auto bt = std::static_pointer_cast<IOS::HLE::Device::BluetoothEmu>(
ios->GetDeviceByName("/dev/usb/oh1/57e/305")); ios->GetDeviceByName("/dev/usb/oh1/57e/305"));
if (bt) if (bt)
bt->AccessWiiMote(wm_idx | 0x100)->Activate(connect); bt->AccessWiiMote(wm_idx | 0x100)->Activate(connect);
const char* message = connect ? "Wii Remote %i connected" : "Wii Remote %i disconnected"; const char* message = connect ? "Wii Remote %i connected" : "Wii Remote %i disconnected";
Core::DisplayMessage(StringFromFormat(message, wm_idx + 1), 3000); Core::DisplayMessage(StringFromFormat(message, wm_idx + 1), 3000);
Host_UpdateMainFrame(); Host_UpdateMainFrame();
Core::PauseAndLock(false, was_unpaused); });
} }
} }
@ -1432,13 +1432,13 @@ void CFrame::OnConnectWiimote(wxCommandEvent& event)
const auto ios = IOS::HLE::GetIOS(); const auto ios = IOS::HLE::GetIOS();
if (!ios || SConfig::GetInstance().m_bt_passthrough_enabled) if (!ios || SConfig::GetInstance().m_bt_passthrough_enabled)
return; return;
bool was_unpaused = Core::PauseAndLock(true); Core::RunAsCPUThread([&] {
const auto bt = std::static_pointer_cast<IOS::HLE::Device::BluetoothEmu>( const auto bt = std::static_pointer_cast<IOS::HLE::Device::BluetoothEmu>(
ios->GetDeviceByName("/dev/usb/oh1/57e/305")); ios->GetDeviceByName("/dev/usb/oh1/57e/305"));
const bool is_connected = const bool is_connected =
bt && bt->AccessWiiMote((event.GetId() - IDM_CONNECT_WIIMOTE1) | 0x100)->IsConnected(); bt && bt->AccessWiiMote((event.GetId() - IDM_CONNECT_WIIMOTE1) | 0x100)->IsConnected();
ConnectWiimote(event.GetId() - IDM_CONNECT_WIIMOTE1, !is_connected); ConnectWiimote(event.GetId() - IDM_CONNECT_WIIMOTE1, !is_connected);
Core::PauseAndLock(false, was_unpaused); });
} }
// Toggle fullscreen. In Windows the fullscreen mode is accomplished by expanding the m_panel to // Toggle fullscreen. In Windows the fullscreen mode is accomplished by expanding the m_panel to
@ -1603,15 +1603,15 @@ void CFrame::UpdateGUI()
GetMenuBar()->FindItem(IDM_CONNECT_BALANCEBOARD)->Enable(ShouldEnableWiimotes); GetMenuBar()->FindItem(IDM_CONNECT_BALANCEBOARD)->Enable(ShouldEnableWiimotes);
if (ShouldEnableWiimotes) if (ShouldEnableWiimotes)
{ {
bool was_unpaused = Core::PauseAndLock(true); Core::RunAsCPUThread([&] {
GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE1)->Check(bt->AccessWiiMote(0x0100)->IsConnected()); GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE1)->Check(bt->AccessWiiMote(0x0100)->IsConnected());
GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE2)->Check(bt->AccessWiiMote(0x0101)->IsConnected()); GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE2)->Check(bt->AccessWiiMote(0x0101)->IsConnected());
GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE3)->Check(bt->AccessWiiMote(0x0102)->IsConnected()); GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE3)->Check(bt->AccessWiiMote(0x0102)->IsConnected());
GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE4)->Check(bt->AccessWiiMote(0x0103)->IsConnected()); GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE4)->Check(bt->AccessWiiMote(0x0103)->IsConnected());
GetMenuBar() GetMenuBar()
->FindItem(IDM_CONNECT_BALANCEBOARD) ->FindItem(IDM_CONNECT_BALANCEBOARD)
->Check(bt->AccessWiiMote(0x0104)->IsConnected()); ->Check(bt->AccessWiiMote(0x0104)->IsConnected());
Core::PauseAndLock(false, was_unpaused); });
} }
GetMenuBar()->FindItem(IDM_RECORD_READ_ONLY)->Enable(Running || Paused); GetMenuBar()->FindItem(IDM_RECORD_READ_ONLY)->Enable(Running || Paused);

View File

@ -915,25 +915,23 @@ void InputConfigDialog::UpdateDeviceComboBox()
void InputConfigDialog::RefreshDevices(wxCommandEvent&) void InputConfigDialog::RefreshDevices(wxCommandEvent&)
{ {
bool was_unpaused = Core::PauseAndLock(true); Core::RunAsCPUThread([&] {
// refresh devices
g_controller_interface.RefreshDevices();
// refresh devices // update all control references
g_controller_interface.RefreshDevices(); UpdateControlReferences();
// update all control references // update device cbox
UpdateControlReferences(); UpdateDeviceComboBox();
// update device cbox Wiimote::LoadConfig();
UpdateDeviceComboBox(); Keyboard::LoadConfig();
Pad::LoadConfig();
HotkeyManagerEmu::LoadConfig();
Wiimote::LoadConfig(); UpdateGUI();
Keyboard::LoadConfig(); });
Pad::LoadConfig();
HotkeyManagerEmu::LoadConfig();
UpdateGUI();
Core::PauseAndLock(false, was_unpaused);
} }
ControlGroupBox::~ControlGroupBox() ControlGroupBox::~ControlGroupBox()