110 lines
4.0 KiB
C++
110 lines
4.0 KiB
C++
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
|
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
|
// ******************************************************************
|
|
// *
|
|
// * This file is part of the Cxbx project.
|
|
// *
|
|
// * Cxbx and Cxbe are free software; you can redistribute them
|
|
// * and/or modify them under the terms of the GNU General Public
|
|
// * License as published by the Free Software Foundation; either
|
|
// * version 2 of the license, or (at your option) any later version.
|
|
// *
|
|
// * 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 for more details.
|
|
// *
|
|
// * You should have recieved a copy of the GNU General Public License
|
|
// * along with this program; see the file COPYING.
|
|
// * If not, write to the Free Software Foundation, Inc.,
|
|
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
|
|
// *
|
|
// * (c) 2021 ergo720
|
|
// *
|
|
// * All rights reserved
|
|
// *
|
|
// ******************************************************************
|
|
|
|
#include <core\kernel\exports\xboxkrnl.h>
|
|
#include <unordered_map>
|
|
#include <shared_mutex>
|
|
#include "Windows.h"
|
|
#include "assert.h"
|
|
#include "NativeHandle.h"
|
|
#include "core\kernel\init\CxbxKrnl.h"
|
|
#include "core/kernel/support/EmuFS.h"
|
|
|
|
|
|
std::unordered_map<xbox::HANDLE, HANDLE> g_RegisteredHandles;
|
|
std::shared_mutex g_MapMtx;
|
|
|
|
void RegisterXboxHandle(xbox::HANDLE xhandle, HANDLE nhandle)
|
|
{
|
|
std::unique_lock<std::shared_mutex> lck(g_MapMtx);
|
|
auto ret = g_RegisteredHandles.try_emplace(xhandle, nhandle);
|
|
if (ret.second == false) {
|
|
// This can happen when an ob handle has been destroyed, but then a thread switch happens before the first thread
|
|
// got a chance to remove the old handle from g_RegisteredHandles with RemoveXboxHandle
|
|
// Test case: dashboard
|
|
auto now = std::chrono::system_clock::now();
|
|
auto timeout = now + std::chrono::milliseconds(2000);
|
|
while (now <= timeout) {
|
|
lck.unlock();
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
|
lck.lock();
|
|
ret = g_RegisteredHandles.try_emplace(xhandle, nhandle);
|
|
if (ret.second) {
|
|
return;
|
|
}
|
|
now += std::chrono::milliseconds(5);
|
|
}
|
|
|
|
// If we reach here, it means that we could not insert the handle after more than two seconds of trying. This probably means
|
|
// that we have forgotten to call RemoveXboxHandle on the old handle, or the other thread is waiting/deadlocked, so this is a bug
|
|
CxbxrAbortEx(CXBXR_MODULE::CXBXR, "Failed to register new xbox handle after more than two seconds!");
|
|
}
|
|
}
|
|
|
|
void RemoveXboxHandle(xbox::HANDLE xhandle)
|
|
{
|
|
std::unique_lock<std::shared_mutex> lck(g_MapMtx);
|
|
[[maybe_unused]] auto ret = g_RegisteredHandles.erase(xhandle);
|
|
assert(ret == 1);
|
|
}
|
|
|
|
template<bool NoConversion>
|
|
std::optional<HANDLE> GetNativeHandle(xbox::HANDLE xhandle)
|
|
{
|
|
// If SourceHandle is -2 = NtCurrentThread, then we are searching the handle of this thread
|
|
// Test case: Metal Slug 3
|
|
if (xhandle == NtCurrentThread()) {
|
|
// Only used for threads as Windows doesn't allow non-special handle for same thread.
|
|
if (NoConversion) {
|
|
return xhandle;
|
|
}
|
|
else {
|
|
xhandle = xbox::PspGetCurrentThread()->UniqueThread;
|
|
}
|
|
}
|
|
// If xhandle is not special handle, check if it's the same as current thread.
|
|
// Only used for threads as Windows doesn't allow non-special handle for same thread.
|
|
// This will only triggered within kernel functions i.e. KeSetDisableBoostThread and KeSetBasePriorityThread.
|
|
else if (NoConversion) {
|
|
if (xhandle == xbox::PspGetCurrentThread()->UniqueThread) {
|
|
return NtCurrentThread();
|
|
}
|
|
}
|
|
|
|
std::shared_lock<std::shared_mutex> lck(g_MapMtx);
|
|
const auto &it = g_RegisteredHandles.find(xhandle);
|
|
if (it == g_RegisteredHandles.end()) {
|
|
return std::nullopt;
|
|
}
|
|
else {
|
|
return it->second;
|
|
}
|
|
}
|
|
|
|
template std::optional<HANDLE> GetNativeHandle<true>(xbox::HANDLE xhandle);
|
|
template std::optional<HANDLE> GetNativeHandle<false>(xbox::HANDLE xhandle);
|