Previous implementation sometimes didn't release the key after pressing
and holding shift due to repeating key updates when holding keys. This
meant repeating updates would set/unset `m_both_shift_keys_pressed`
repeatedly, sometimes resulting in shift still being considered pressed
even after you released it.
Simplify left and right shift key pressed logic by tracking both key
states separately and always updating modifiers based on them.
Initializing the variable this way fixes a kernel panic in Clang where
the object was zero-initialized, so the `m_in_scheduler` contained the
wrong value. GCC got it right, but we're better off making this change,
as leaving uninitialized fields in constant-initialized objects can
cause other weird situations like this. Also, initializing only a single
field to a non-zero value isn't worth the cost of no longer fitting in
`.bss`.
Another two variables suffer from the same problem, even though their
values are supposed to be zero. Removing these causes the
`_GLOBAL_sub_I_` function to no longer be generated and the (not
handled) `.init_array` section to be omitted.
This avoids a race between getting the processor-specific SchedulerData
and accessing it. (Switching to a different CPU in that window means
that we're operating on the wrong SchedulerData.)
Co-authored-by: Tom <tomut@yahoo.com>
Prior to this change, both uid_t and gid_t were typedef'ed to `u32`.
This made it easy to use them interchangeably. Let's not allow that.
This patch adds UserID and GroupID using the AK::DistinctNumeric
mechanism we've already been employing for pid_t/ProcessID.
Add a dummy Arch/aarch64/boot.S that for now does nothing but
let all processor cores sleep.
For now, none of the actual Prekernel code is built for aarch64.
This should help prevent deadlocks where a thread blocks on a Mutex
while interrupts are disabled, and makes it impossible for the holder of
the Mutex to make forward progress because it cannot be scheduled in.
Hide it behind a new debug macro LOCK_IN_CRITICAL_DEBUG for now, because
Ext2FS takes a series of Mutexes from the page fault handler, which
executes with interrupts disabled.
Previously, we would try to acquire a reference to the all processes
lock or other contended resources while holding both the scheduler lock
and the thread's blocker lock. This could lead to a deadlock if we
actually have to block on those other resources.
There are callers of processes().with or processes().for_each that
require interrupts to be disabled. Taking a Mutexe with interrupts
disabled is a recipe for deadlock, so convert this to a Spinlock.
There's no need to disable interrupts when trying to access an inode's
shared vmobject. Additionally, Inode::shared_vmobject() acquires a Mutex
which is a recipe for deadlock if acquired with interrupts disabled.
Two new ioctl requests are used to get and set the sample rate of the
sound card. The SB16 device keeps track of the sample rate separately,
because I don't want to figure out how to read the sample rate from the
device; it's easier that way.
The soundcard write doesn't set the sample rate to 44100 Hz every time
anymore, as we want to change it externally.
In order to use VirtualAddresses as compile time constants in the
AddressSanitizer implementation, we need to be able to use these
methods in constexpr functions / variable initializations.
The pattern of having Prekernel inherit all of the build flags of the
Kernel, and then disabling some flags by adding `-fno-<flag>` options
to then disable those options doesn't work in all scenarios. For example
the ASAN flag `-fasan-shadow-offset=<offset>` has no option to disable
it once it's been passed, so in a future change where this flag is added
we need to be able to disable it cleanly.
The cleaner way is to just allow the Prekernel CMake logic to filter out
the COMPILE_OPTIONS specified for that specific target. This allows us
to remove individual options without trashing all inherited options.
We have seen cases where the map fails, but we return the region
to the caller, causing them to page fault later on when they touch
the region.
The fix is to always observe the return code of map/remap.
Let's use an RAII helper to avoid having to update this on every path
out of block().
Note that this extends the time under `m_in_block == true` by a little
but that should be harmless.
The `m_should_block` member variable that many of the Thread::Blocker
subclasses had was really only used to carry state from the constructor
to the immediate-unblock-without-blocking escape hatch.
This patch refactors the blockers so that we don't need to hold on
to this flag after setup_blocker(), and instead the return value from
setup_blocker() is the authority on whether the unblock conditions
are already met.
This was previously used after construction to check for early unblock
conditions that couldn't be communicated from the constructor.
Now that we've moved early unblock checks from the constructor into
setup_blocker(), we don't need should_block() anymore.
Instead of registering with blocker sets and whatnot in the various
Blocker subclass constructors, this patch moves such initialization
to a separate setup_blocker() virtual.
setup_blocker() returns false if there's no need to actually block
the thread. This allows us to bail earlier in Thread::block().
Same deal as WaitQueueBlocker, we can get the blocked thread from
Blocker::thread() now, so there's no need to register the current
thread as custom data.
When adding a WaitQueueBlocker to a WaitQueue, it stored the blocked
thread in the registration's custom "void* data" slot.
This was only used to print the Thread* in some debug logging.
Now that Blocker always knows its origin Thread, we can simply add
a Blocker::thread() accessor and then get the blocked Thread& from
there. No need to register custom data.
There's no harm in the blocker always knowing which thread it originated
from. It also simplifies some logic since we don't need to think about
it ever being null.
The BlockerSet stores its blockers along with a "void* data" that may
contain some blocker-specific context relevant to the specific blocker
registration (for example, SelectBlocker stores a pointer to the
relevant entry in an array of SelectBlocker::FDInfo structs.)
When unregistering a blocker from a set, we don't need to key the
blocker by both the Blocker* and the data. Just the Blocker* is enough,
since all registrations for that blocker need to be removed anyway as
the blocker is about to be destroyed.
So we stop passing the "void* data" to BlockerSet::remove_blocker(),
which also allows us to remove the now-unneeded Blocker::m_block_data.