Fix issues with not being able to run ROMs concurrently

This commit fixes GroupMutex and by extension issues with trying to run ROMs without quitting the application in between.
This commit is contained in:
◱ PixelyIon 2020-02-06 00:07:45 +05:30 committed by ◱ PixelyIon
parent 694c8ef4e2
commit 003e9c5a01
10 changed files with 49 additions and 33 deletions

View File

@ -18,20 +18,18 @@ namespace skyline {
void GroupMutex::lock(Group group) { void GroupMutex::lock(Group group) {
auto none = Group::None; auto none = Group::None;
if (flag == group) { constexpr u64 timeout = 1000; // The timeout in ns
num++; auto start = utils::GetTimeNs();
return; while (next != group && !next.compare_exchange_weak(none, group)) {
} if (flag == group && ((utils::GetTimeNs() - start) > timeout)) {
while (true) { num++;
for (int i = 0; i < 1000; ++i) { return;
if (flag.compare_exchange_weak(none, group)) {
num++;
return;
}
asm volatile("yield");
} }
sched_yield(); asm volatile("yield");
} }
while (flag != group && !flag.compare_exchange_weak(none, group))
asm volatile("yield");
num++;
} }
void GroupMutex::unlock() { void GroupMutex::unlock() {
@ -51,11 +49,11 @@ namespace skyline {
break; break;
case 'b': case 'b':
boolMap[elem->FindAttribute("name")->Value()] = elem->FindAttribute( boolMap[elem->FindAttribute("name")->Value()] = elem->FindAttribute(
"value")->BoolValue(); "value")->BoolValue();
break; break;
case 'i': case 'i':
intMap[elem->FindAttribute("name")->Value()] = elem->FindAttribute( intMap[elem->FindAttribute("name")->Value()] = elem->FindAttribute(
"value")->IntValue(); "value")->IntValue();
break; break;
default: default:
syslog(LOG_ALERT, "Settings type is missing: %s for %s", elem->Value(), syslog(LOG_ALERT, "Settings type is missing: %s for %s", elem->Value(),

View File

@ -100,12 +100,19 @@ namespace skyline {
* @brief Returns the current time in nanoseconds * @brief Returns the current time in nanoseconds
* @return The current time in nanoseconds * @return The current time in nanoseconds
*/ */
inline u64 GetCurrTimeNs() { inline u64 GetTimeNs() {
return static_cast<u64>(std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count()); static u64 frequencyMs{};
if (!frequencyMs) {
asm("MRS %0, CNTFRQ_EL0" : "=r"(frequencyMs));
frequencyMs *= 1000000000;
}
u64 ticks;
asm("MRS %0, CNTVCT_EL0" : "=r"(ticks));
return ticks / frequencyMs;
} }
/** /**
* @brief Aligns up a value to a multiple of two * @brief Aligns up a value to a multiple of twoB
* @tparam Type The type of the values * @tparam Type The type of the values
* @param value The value to round up * @param value The value to round up
* @param multiple The multiple to round up to (Should be a multiple of 2) * @param multiple The multiple to round up to (Should be a multiple of 2)
@ -113,7 +120,7 @@ namespace skyline {
* @tparam TypeMul The type of the multiple * @tparam TypeMul The type of the multiple
* @return The aligned value * @return The aligned value
*/ */
template <typename TypeVal, typename TypeMul> template<typename TypeVal, typename TypeMul>
inline TypeVal AlignUp(TypeVal value, TypeMul multiple) { inline TypeVal AlignUp(TypeVal value, TypeMul multiple) {
static_assert(std::is_integral<TypeVal>() && std::is_integral<TypeMul>()); static_assert(std::is_integral<TypeVal>() && std::is_integral<TypeMul>());
multiple--; multiple--;
@ -128,7 +135,7 @@ namespace skyline {
* @tparam TypeMul The type of the multiple * @tparam TypeMul The type of the multiple
* @return The aligned value * @return The aligned value
*/ */
template <typename TypeVal, typename TypeMul> template<typename TypeVal, typename TypeMul>
inline TypeVal AlignDown(TypeVal value, TypeMul multiple) { inline TypeVal AlignDown(TypeVal value, TypeMul multiple) {
static_assert(std::is_integral<TypeVal>() && std::is_integral<TypeMul>()); static_assert(std::is_integral<TypeVal>() && std::is_integral<TypeMul>());
multiple--; multiple--;
@ -207,6 +214,7 @@ namespace skyline {
private: private:
std::atomic<Group> flag = Group::None; //!< An atomic flag to hold which group holds the mutex std::atomic<Group> flag = Group::None; //!< An atomic flag to hold which group holds the mutex
std::atomic<Group> next = Group::None; //!< An atomic flag to hold which group will hold the mutex next
std::atomic<u8> num = 0; //!< An atomic u8 keeping track of how many users are holding the mutex std::atomic<u8> num = 0; //!< An atomic u8 keeping track of how many users are holding the mutex
}; };

View File

@ -87,7 +87,7 @@ namespace skyline::kernel {
} }
void MemoryManager::InitializeRegions(u64 address, u64 size, const memory::AddressSpaceType type) { void MemoryManager::InitializeRegions(u64 address, u64 size, const memory::AddressSpaceType type) {
switch(type) { switch (type) {
case memory::AddressSpaceType::AddressSpace32Bit: case memory::AddressSpaceType::AddressSpace32Bit:
throw exception("32-bit address spaces are not supported"); throw exception("32-bit address spaces are not supported");
case memory::AddressSpaceType::AddressSpace36Bit: { case memory::AddressSpaceType::AddressSpace36Bit: {
@ -95,7 +95,7 @@ namespace skyline::kernel {
base.size = 0xFF8000000; base.size = 0xFF8000000;
code.address = base.address; code.address = base.address;
code.size = 0x78000000; code.size = 0x78000000;
if(code.address > address || (code.size - (address - code.address)) < size) if (code.address > address || (code.size - (address - code.address)) < size)
throw exception("Code mapping larger than 36-bit code region"); throw exception("Code mapping larger than 36-bit code region");
alias.address = code.address + code.size; alias.address = code.address + code.size;
alias.size = 0x180000000; alias.size = 0x180000000;
@ -124,7 +124,7 @@ namespace skyline::kernel {
} }
} }
state.logger->Debug("Region Map:\nCode Region: 0x{:X} - 0x{:X} (Size: 0x{:X})\nAlias Region: 0x{:X} - 0x{:X} (Size: 0x{:X})\nHeap Region: 0x{:X} - 0x{:X} (Size: 0x{:X})\nStack Region: 0x{:X} - 0x{:X} (Size: 0x{:X})\nTLS/IO Region: 0x{:X} - 0x{:X} (Size: 0x{:X})", code.address, code.address + code.size, code.size, alias.address, alias.address + alias.size, alias.size, heap.address, heap state.logger->Debug("Region Map:\nCode Region: 0x{:X} - 0x{:X} (Size: 0x{:X})\nAlias Region: 0x{:X} - 0x{:X} (Size: 0x{:X})\nHeap Region: 0x{:X} - 0x{:X} (Size: 0x{:X})\nStack Region: 0x{:X} - 0x{:X} (Size: 0x{:X})\nTLS/IO Region: 0x{:X} - 0x{:X} (Size: 0x{:X})", code.address, code.address + code.size, code.size, alias.address, alias.address + alias.size, alias.size, heap.address, heap
.address + heap.size, heap.size, stack.address, stack.address + stack.size, stack.size, tlsIo.address, tlsIo.address + tlsIo.size, tlsIo.size); .address + heap.size, heap.size, stack.address, stack.address + stack.size, stack.size, tlsIo.address, tlsIo.address + tlsIo.size, tlsIo.size);
} }
MemoryManager::MemoryManager(const DeviceState &state) : state(state) {} MemoryManager::MemoryManager(const DeviceState &state) : state(state) {}
@ -139,7 +139,7 @@ namespace skyline::kernel {
} }
memory::Region MemoryManager::GetRegion(memory::Regions region) { memory::Region MemoryManager::GetRegion(memory::Regions region) {
switch(region) { switch (region) {
case memory::Regions::Base: case memory::Regions::Base:
return base; return base;
case memory::Regions::Code: case memory::Regions::Code:

View File

@ -120,6 +120,7 @@ namespace skyline {
*/ */
union MemoryState { union MemoryState {
constexpr MemoryState(const u32 value) : value(value) {}; constexpr MemoryState(const u32 value) : value(value) {};
constexpr MemoryState() : value(0) {}; constexpr MemoryState() : value(0) {};
struct { struct {
@ -226,6 +227,7 @@ namespace skyline {
namespace svc { namespace svc {
void SetMemoryAttribute(DeviceState &state); void SetMemoryAttribute(DeviceState &state);
void MapMemory(DeviceState &state); void MapMemory(DeviceState &state);
} }
@ -324,7 +326,9 @@ namespace skyline {
friend class type::KTransferMemory; friend class type::KTransferMemory;
friend class type::KProcess; friend class type::KProcess;
friend class loader::NroLoader; friend class loader::NroLoader;
friend void svc::SetMemoryAttribute(DeviceState &state); friend void svc::SetMemoryAttribute(DeviceState &state);
friend void svc::MapMemory(skyline::DeviceState &state); friend void svc::MapMemory(skyline::DeviceState &state);
MemoryManager(const DeviceState &state); MemoryManager(const DeviceState &state);

View File

@ -377,7 +377,7 @@ namespace skyline::kernel::svc {
} }
auto timeout = state.ctx->registers.x3; auto timeout = state.ctx->registers.x3;
state.logger->Debug("svcWaitSynchronization: Waiting on handles:\n{}Timeout: 0x{:X} ns", handleStr, timeout); state.logger->Debug("svcWaitSynchronization: Waiting on handles:\n{}Timeout: 0x{:X} ns", handleStr, timeout);
auto start = utils::GetCurrTimeNs(); auto start = utils::GetTimeNs();
while (true) { while (true) {
if (state.thread->cancelSync) { if (state.thread->cancelSync) {
state.thread->cancelSync = false; state.thread->cancelSync = false;
@ -394,7 +394,7 @@ namespace skyline::kernel::svc {
} }
index++; index++;
} }
if ((utils::GetCurrTimeNs() - start) >= timeout) { if ((utils::GetTimeNs() - start) >= timeout) {
state.logger->Debug("svcWaitSynchronization: Wait has timed out"); state.logger->Debug("svcWaitSynchronization: Wait has timed out");
state.ctx->registers.w0 = constant::status::Timeout; state.ctx->registers.w0 = constant::status::Timeout;
return; return;

View File

@ -124,7 +124,9 @@ namespace skyline::kernel::type {
} catch (const std::exception &) { } catch (const std::exception &) {
} }
auto chunk = state.os->memory.GetChunk(address); auto chunk = state.os->memory.GetChunk(address);
munmap(reinterpret_cast<void *>(chunk->host), chunk->size); if (chunk) {
state.os->memory.DeleteChunk(address); munmap(reinterpret_cast<void *>(chunk->host), chunk->size);
state.os->memory.DeleteChunk(address);
}
} }
}; };

View File

@ -211,7 +211,7 @@ namespace skyline::kernel::type {
auto status = (*mtxWaiters.begin()); auto status = (*mtxWaiters.begin());
status->flag = true; status->flag = true;
lock.unlock(); lock.unlock();
while(status->flag); while (status->flag);
lock.lock(); lock.lock();
} }
return true; return true;
@ -230,9 +230,9 @@ namespace skyline::kernel::type {
} }
lock.unlock(); lock.unlock();
bool timedOut{}; bool timedOut{};
auto start = utils::GetCurrTimeNs(); auto start = utils::GetTimeNs();
while (!status->flag) { while (!status->flag) {
if ((utils::GetCurrTimeNs() - start) >= timeout) if ((utils::GetTimeNs() - start) >= timeout)
timedOut = true; timedOut = true;
} }
lock.lock(); lock.lock();
@ -298,7 +298,7 @@ namespace skyline::kernel::type {
iter++; iter++;
count++; count++;
condLock.unlock(); condLock.unlock();
while(thread->flag); while (thread->flag);
condLock.lock(); condLock.lock();
} }
} }

View File

@ -186,8 +186,8 @@ namespace skyline::kernel::type {
* @note This can return a nullptr if the address is invalid * @note This can return a nullptr if the address is invalid
*/ */
template<typename Type> template<typename Type>
inline Type* GetPointer(const u64 address) const { inline Type *GetPointer(const u64 address) const {
return reinterpret_cast<Type*>(GetHostAddress(address)); return reinterpret_cast<Type *>(GetHostAddress(address));
} }
/** /**

View File

@ -93,6 +93,8 @@ namespace skyline {
} }
void NCE::ExecuteFunction(ThreadCall call, Registers &funcRegs) { void NCE::ExecuteFunction(ThreadCall call, Registers &funcRegs) {
if(state.process->status == kernel::type::KProcess::Status::Exiting)
throw exception("Executing function on Exiting process");
auto thread = state.thread ? state.thread : state.process->threads.at(state.process->pid); auto thread = state.thread ? state.thread : state.process->threads.at(state.process->pid);
ExecuteFunctionCtx(call, funcRegs, reinterpret_cast<ThreadContext *>(thread->ctxMemory->kernel.address)); ExecuteFunctionCtx(call, funcRegs, reinterpret_cast<ThreadContext *>(thread->ctxMemory->kernel.address));
} }

View File

@ -278,8 +278,10 @@ namespace skyline::guest {
.sa_sigaction = reinterpret_cast<void (*)(int, struct siginfo *, void *)>(reinterpret_cast<void *>(signalHandler)), .sa_sigaction = reinterpret_cast<void (*)(int, struct siginfo *, void *)>(reinterpret_cast<void *>(signalHandler)),
.sa_flags = SA_SIGINFO, .sa_flags = SA_SIGINFO,
}; };
/*
for (int signal : {SIGILL, SIGTRAP, SIGBUS, SIGFPE, SIGSEGV}) for (int signal : {SIGILL, SIGTRAP, SIGBUS, SIGFPE, SIGSEGV})
sigaction(signal, &sigact, nullptr); sigaction(signal, &sigact, nullptr);
*/
ctx->state = ThreadState::Running; ctx->state = ThreadState::Running;
asm("MOV LR, %0\n\t" asm("MOV LR, %0\n\t"
"MOV X0, %1\n\t" "MOV X0, %1\n\t"