| Commit message (Collapse) | Author | Age | Files | Lines |
|\
| |
| | |
kernel/svc: Clean up wait synchronization related functionality
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
This is a holdover from Citra, where the 3DS has both
WaitSynchronization1 and WaitSynchronizationN. The switch only has one
form of wait synchronizing (literally WaitSynchonization). This allows
us to throw out code that doesn't apply at all to the Switch kernel.
Because of this unnecessary dichotomy within the wait synchronization
utilities, we were also neglecting to properly handle waiting on
multiple objects.
While we're at it, we can also scrub out any lingering references to
WaitSynchronization1/WaitSynchronizationN in comments, and change them
to WaitSynchronization (or remove them if the mention no longer
applies).
|
| |
| |
| |
| |
| |
| |
| | |
The actual behavior of this function is slightly more complex than what
we're currently doing within the supervisor call. To avoid dumping most
of this behavior in the supervisor call itself, we can migrate this to
another function.
|
|\ \
| |/
|/| |
kernel/thread: Remove unused guest_handle member variable
|
| |
| |
| |
| | |
Allows the handle to be seen alongside the entry point.
|
| |
| |
| |
| |
| |
| | |
This member variable is entirely unused. It was only set but never
actually utilized. Given that, we can remove it to get rid of noise in
the thread interface.
|
|/
|
|
|
| |
This is a holdover from Citra that currently remains unused, so it can
be removed from the Thread interface.
|
|
|
|
|
|
|
| |
Some objects declare their handle type as const, while others declare it
as constexpr. This makes the const ones constexpr for consistency, and
prevent unexpected compilation errors if these happen to be attempted to be
used within a constexpr context.
|
|
|
|
|
|
| |
Now that ShouldWait() is a const qualified member function, this one can
be made const qualified as well, since it can handle passing a const
qualified this pointer to ShouldWait().
|
|
|
|
|
| |
Given this is intended as a querying function, it doesn't make sense to
allow the implementer to modify the state of the given thread.
|
|
|
|
|
| |
The pointed to member is never actually modified, so it can be made
const.
|
| |
|
|\
| |
| | |
kernel/thread: Amend conditional test and assignment within UpdatePriority()
|
| |
| |
| |
| |
| | |
Aims to disambiguate why each priority instance exists a little bit.
While we're at it, also add an explanatory comment to UpdatePriority().
|
| |
| |
| |
| |
| | |
Puts the operation on global state in the same places as the rest of the
svc calls.
|
|/
|
|
|
|
| |
Rather than make a global accessor for this sort of thing. We can make
it a part of the thread interface itself. This allows getting rid of a
hidden global accessor in the kernel code.
|
|
|
|
|
|
| |
This makes the naming more closely match its meaning. It's just a
preferred core, not a required default core. This also makes the usages
of this term consistent across the thread and process implementations.
|
|
|
|
|
|
|
|
|
|
| |
This function isn't a general purpose function that should be exposed to
everything, given it's specific to initializing the main thread for a
Process instance.
Given that, it's a tad bit more sensible to place this within
process.cpp, which keeps it visible only to the code that actually needs
it.
|
|\
| |
| | |
svc: Implement SetThreadActivity (thread suspension)
|
| | |
|
| |
| |
| |
| |
| | |
The kernel uses a 64-bit value for the thread ID, so we shouldn't be
using a 32-bit value.
|
| | |
|
|/ |
|
|
|
|
|
| |
The code in both places was the same verbatim, so we can extract it to a
function to deduplicate the logic.
|
|
|
|
|
|
|
|
|
|
| |
This retrieves:
if (curr_thread == handle_thread) {
result = total_thread_ticks + (hardware_tick_count - last_context_switch_ticks);
} else if (curr_thread == handle_thread && sub_id == current_core_index) {
result = hardware_tick_count - last_context_switch_ticks;
}
|
|
|
|
|
|
|
|
|
|
|
| |
There's no real need to use a shared pointer in these cases, and only
makes object management more fragile in terms of how easy it would be to
introduce cycles. Instead, just do the simple thing of using a regular
pointer. Much of this is just a hold-over from citra anyways.
It also doesn't make sense from a behavioral point of view for a
process' thread to prolong the lifetime of the process itself (the
process is supposed to own the thread, not the other way around).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Conceptually, it doesn't make sense for a thread to be able to persist
the lifetime of a scheduler. A scheduler should be taking care of the
threads; the threads should not be taking care of the scheduler.
If the threads outlive the scheduler (or we simply don't actually
terminate/shutdown the threads), then it should be considered a bug
that we need to fix.
Attributing this to balika011, as they opened #1317 to attempt to fix
this in a similar way, but my refactoring of the kernel code caused
quite a few conflicts.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Many of the member variables of the thread class aren't even used
outside of the class itself, so there's no need to make those variables
public. This change follows in the steps of the previous changes that
made other kernel types' members private.
The main motivation behind this is that the Thread class will likely
change in the future as emulation becomes more accurate, and letting
random bits of the emulator access data members of the Thread class
directly makes it a pain to shuffle around and/or modify internals.
Having all data members public like this also makes it difficult to
reason about certain bits of behavior without first verifying what parts
of the core actually use them.
Everything being public also generally follows the tendency for changes
to be introduced in completely different translation units that would
otherwise be better introduced as an addition to the Thread class'
public interface.
|
|
|
|
|
|
| |
Allows making several members of the process class private, it also
avoids going through Core::CurrentProcess() just to retrieve the owning
process.
|
|
|
|
|
|
|
| |
The owning process of a thread is required to exist before the thread,
so we can enforce this API-wise by using a reference. We can also avoid
the reliance on the system instance by using that parameter to access
the page table that needs to be set.
|
| |
|
|
|
|
|
|
| |
Previously, these were sitting outside of the Kernel namespace, which
doesn't really make sense, given they're related to the Thread class
which is within the Kernel namespace.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
As means to pave the way for getting rid of global state within core,
This eliminates kernel global state by removing all globals. Instead
this introduces a KernelCore class which acts as a kernel instance. This
instance lives in the System class, which keeps its lifetime contained
to the lifetime of the System class.
This also forces the kernel types to actually interact with the main
kernel instance itself instead of having transient kernel state placed
all over several translation units, keeping everything together. It also
has a nice consequence of making dependencies much more explicit.
This also makes our initialization a tad bit more correct. Previously we
were creating a kernel process before the actual kernel was initialized,
which doesn't really make much sense.
The KernelCore class itself follows the PImpl idiom, which allows
keeping all the implementation details sealed away from everything else,
which forces the use of the exposed API and allows us to avoid any
unnecessary inclusions within the main kernel header.
|
|
|
|
| |
Gets all of these types and interfaces out of the global namespace.
|
|
|
|
|
|
| |
This amends cases where crashes can occur that were missed due to the
odd way the previous code was set up (using 3DS memory regions that
don't exist).
|
|
|
|
|
|
| |
General moving to keep kernel object types separate from the direct
kernel code. Also essentially a preliminary cleanup before eliminating
global kernel state in the kernel code.
|
|
|
|
|
| |
Given there's no implementation, we may as well remove the code
entirely.
|
|
|
|
|
| |
Removes unnecessary direct dependencies in some headers and also gets
rid of indirect dependencies that were being relied on to be included.
|
|\
| |
| | |
CPU: Save and restore the TPIDR_EL0 system register on every context switch
|
| |
| |
| |
| | |
Note that there's currently a dynarmic bug preventing this register from being written.
|
|/
|
|
|
| |
Makes the thread status strongly typed, so implicit conversions can't
happen. It also makes it easier to catch mistakes at compile time.
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
|
|
|
|
|
|
| |
Verified with a hwtest and implemented based on reverse engineering.
Thread A's priority will get bumped to the highest priority among all the threads that are waiting for a mutex that A holds.
Once A releases the mutex and ownership is transferred to B, A's priority will return to normal and B's priority will be bumped.
|
| |
|
| |
|
| |
|
|
|
|
|
|
|
|
|
|
| |
Switch mutexes are no longer kernel objects, they are managed in userland and only use the kernel to handle the contention case.
Mutex addresses store a special flag value (0x40000000) to notify the guest code that there are still some threads waiting for the mutex to be released. This flag is updated when a thread calls ArbitrateUnlock.
TODO:
* Fix svcWaitProcessWideKey
* Fix svcSignalProcessWideKey
* Remove the Mutex class.
|
| |
|
| |
|
| |
|
|
|
|
|
|
|
|
| |
Ported from citra PR #3091
The delay specified here is from a Nintendo 3DS, and should be measured in a Nintendo Switch.
This change is enough to prevent Puyo Puyo Tetris's main thread starvation.
|
| |
|
| |
|
|
|
|
| |
This is kinda crufty, but we need it for now to update guest state variables.
|
| |
|
|\
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
# Conflicts:
# src/core/CMakeLists.txt
# src/core/arm/dynarmic/arm_dynarmic.cpp
# src/core/arm/dyncom/arm_dyncom.cpp
# src/core/hle/kernel/process.cpp
# src/core/hle/kernel/thread.cpp
# src/core/hle/kernel/thread.h
# src/core/hle/kernel/vm_manager.cpp
# src/core/loader/3dsx.cpp
# src/core/loader/elf.cpp
# src/core/loader/ncch.cpp
# src/core/memory.cpp
# src/core/memory.h
# src/core/memory_setup.h
|
| |\
| | |
| | | |
Memory: Add overloads for ReadBlock and WriteBlock that operate on a specific process.
|
| | | |
|
| |\ \
| | |/
| |/| |
Kernel/Threads: When putting a thread to wait, specify a function to execute when it is awoken
|
| | |
| | |
| | |
| | |
| | |
| | | |
This change makes for a clearer (less confusing) path of execution in the scheduler, now the code to execute when a thread awakes is closer to the code that puts the thread to sleep (WaitSynch1, WaitSynchN). It also allows us to implement the special wake up behavior of ReplyAndReceive without hacking up WaitObject::WakeupAllWaitingThreads.
If savestates are desired in the future, we can change this implementation to one similar to the CoreTiming event system, where we first register the callback functions at startup and assign their identifiers to the Thread callback variable instead of directly assigning a lambda to the wake up callback variable.
|
| | | |
|
| |/
| |
| |
| | |
Don't automatically assume that Thread::Create will only be called when the parent process is currently scheduled. This assumption will be broken when applets or system modules are loaded.
|
|/ |
|
|
|
|
|
| |
Now that HandleTable doesn't directly depend on WaitObject anymore, this
can be separated from the main kernel.h header.
|
| |
|
| |
|
|\
| |
| | |
Don't yield execution in SleepThread(0) if there are no available threads to run
|
| |
| |
| |
| | |
With this we avoid an useless temporary deschedule of the current thread.
|
|/ |
|
| |
|
|
|
|
|
|
|
|
| |
This commit removes the overly general THREADSTATUS_WAIT_SYNCH and replaces it with two more granular statuses:
THREADSTATUS_WAIT_SYNCH_ANY when a thread waits on objects via WaitSynchronization1 or WaitSynchronizationN with wait_all = false.
THREADSTATUS_WAIT_SYNCH_ALL when a thread waits on objects via WaitSynchronizationN with wait_all = true.
|
| |
|
|
|
|
| |
This will be useful when implementing mutex priority inheritance.
|
| |
|
| |
|
| |
|
| |
|
|
|
|
|
|
| |
Define a variable with the value of the sync timeout error code.
Use a boost::flat_map instead of an unordered_map to hold the equivalence of objects and wait indices in a WaitSynchN call.
|
| |
|
|
|
|
|
|
|
|
|
|
| |
Threads will now be awakened when the objects they're waiting on are signaled, instead of repeating the WaitSynchronization call every now and then.
The scheduler is now called once after every SVC call, and once after a thread is awakened from sleep by its timeout callback.
This new implementation is based off reverse-engineering of the real kernel.
See https://gist.github.com/Subv/02f29bd9f1e5deb7aceea1e8f019c8f4 for a more detailed description of how the real kernel handles rescheduling.
|
| |
|
|
|
|
|
|
|
| |
This makes clang-format useful on those.
Also add a bunch of forgotten transitive includes, which otherwise
prevented compilation.
|
| |
|
|
|
|
|
|
| |
Each thread gets a 0x200-byte area from the 0x1000-sized page, when all 8 thread slots in a single page are used up, the kernel allocates a new page to hold another 8 entries.
This is consistent with what the real kernel does.
|
| |
|
| |
|
| |
|
| |
|
|
|
|
|
|
|
| |
memory.cpp/h contains definitions related to acessing memory and
configuring the address space
mem_map.cpp/h contains higher-level definitions related to configuring
the address space accoording to the kernel and allocating memory.
|
|\
| |
| | |
Core/Memory: Add TLS support for creating up to 300 threads
|
| | |
|
|\ \
| |/
|/| |
Thread: Remove the idle thread
|
| |
| |
| |
| | |
Instead just use nullptr to represent no thread is active.
|
|\ \
| |/
|/| |
Core/HLE: Implemented the SVCs GetProcessId and GetProcessIdOfThread
|
| | |
|
|/ |
|
| |
|
|
|
|
|
| |
The TLS area for thread T with id Ti is located at TLS_AREA_VADDR + (Ti - 1) * 0x200.
This allows some games like Mario Kart 7 to continue further.
|
| |
|
| |
|
|
|
|
|
|
| |
SVC: Return correct error code on invalid CreateThread processor ID.
SVC: Assert when creating a thread with an invalid userland priority.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
* Simplifies scheduling logic, specifically regarding thread status. It should be much clearer which statuses are valid
for a thread at any given point in the system.
* Removes dead code from thread.cpp.
* Moves the implementation of resetting a ThreadContext to the corresponding core's implementation.
Other changes:
* Fixed comments in arm interfaces.
* Updated comments in thread.cpp
* Removed confusing, useless, functions like MakeReady() and ChangeStatus() from thread.cpp.
* Removed stack_size from Thread. In the CTR kernel, the thread's stack would be allocated before thread creation.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
During normal operation, a thread waiting on an WaitObject and the
object hold mutual references to each other for the duration of the
wait.
If a process is forcefully terminated (The CTR kernel has a SVC to do
this, TerminateProcess, though no equivalent exists for threads.) its
threads would also be stopped and destroyed, leaving dangling pointers
in the WaitObjects.
The solution is to simply have the Thread remove itself from WaitObjects
when it is stopped. The vector of Threads in WaitObject has also been
changed to hold SharedPtrs, just in case. (Better to have a reference
cycle than a crash.)
|
|
|
|
|
|
| |
This should speed up compile times a bit, as well as enable more liberal
use of forward declarations. (Due to SharedPtr not trying to emit the
destructor anymore.)
|
| |
|
|
|
|
| |
This is to support the removal of GetHandle soon
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
|
|
|
|
|
| |
- Separate wait checking from waiting the current thread
- Resume thread when wait_all=true only if all objects are available at once
- Set output to correct wait object index when there are duplicate handles
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
|\
| |
| | |
Implemented timers
|
| | |
|
| |
| |
| |
| | |
It will now properly wait the specified number of nanoseconds and then wake up the thread.
|
|/
|
|
| |
This thread will not actually execute instructions, it will only advance the timing/events and try to yield immediately to the next ready thread, if there aren't any ready threads then it will be rescheduled and start its job again.
|
|
|
|
|
|
|
|
|
|
|
| |
This handle manager more closely mirrors the behaviour of the CTR-OS
one. In addition object ref-counts and support for DuplicateHandle have
been added.
Note that support for DuplicateHandle is still experimental, since parts
of the kernel still use Handles internally, which will likely cause
troubles if two different handles to the same object are used to e.g.
wait on a synchronization primitive.
|
|\
| |
| | |
License change
|
| | |
|
| |
| |
| |
| |
| |
| | |
- Removed unused VBLANK sleep mode
- Added error log for bad context switch
- Renamed VerifyWait to CheckWaitType to be more clear
|
|/
|
|
| |
This boots a few (mostly Nintendo 1st party) games further.
|
| |
|
| |
|
|
|
|
| |
For now threads are using their Handle value as their Id, it should not really cause any problems because Handle values are unique in Citra, but it should be changed. I left a ToDo there because this is not correct behavior as per hardware.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
All service calls in the CTR OS return result codes indicating the
success or failure of the call. Previous to this commit, Citra's HLE
emulation of services and the kernel universally either ignored errors
or returned dummy -1 error codes.
This commit makes an initial effort to provide an infrastructure for
error reporting and propagation which can be use going forward to make
HLE calls accurately return errors as the original system. A few parts
of the code have been updated to use the new system where applicable.
One part of this effort is the definition of the `ResultCode` type,
which provides facilities for constructing and parsing error codes in
the structured format used by the CTR.
The `ResultVal` type builds on `ResultCode` by providing a container for
values returned by function that can report errors. It enforces that
correct error checking will be done on function returns by preventing
the use of the return value if the function returned an error code.
Currently this change is mostly internal since errors are still
suppressed on the ARM<->HLE border, as a temporary compatibility hack.
As functionality is implemented and tested this hack can be eventually
removed.
|
| |
|
| |
|
|
|
|
|
|
| |
Thread: Cleaned up arbitrate address functions.
Thread: Cleaned up ArbitrateAllThreads function.
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
- SVC: Added ExitThread support
- SVC: Added SignalEvent support
- Thread: Added WAITTYPE_EVENT for waiting threads for event signals
- Thread: Added support for blocking on other threads to finish (e.g. Thread::Join)
- Thread: Added debug function for printing current threads ready for execution
- Thread: Removed hack/broken thread ready state code from Kernel::Reschedule
- Mutex: Moved WaitCurrentThread from SVC to Mutex::WaitSynchronization
- Event: Added support for blocking threads on event signalling
Kernel: Added missing algorithm #include for use of std::find on non-Windows platforms.
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
|
|
|
|
| |
- cleaned up Kernel code a bit (moved stuff into namespace, fixed whitespace issues)
- added handle types for all different CTROS handles
|
| |
|
| |
|
|
|
|
|
| |
- reorganized some kernel thread functions
- added placeholder __KernelWaitThread_Synchronization function
|
|
|
|
| |
- added KERNEL_DEFAULT_STACK_SIZE definition (0x4000)
|
| |
|
|
|
|
|
| |
- added __KernelSwitchToThread for enabling a thread
- added __KernelRotateThreadReadyQueue
|
| |
|
| |
|
|
|