This is the closest Windows equivalent to integrating process exit
handlers into the event loop.
Linux could also integrate register_process() into the poll() based
Unix event loop via the SYS_pidfd_open syscall; however, macOS requires
a kqueue. So for now register_process will only be used by Windows to
implement WebView::ProcessMonitor.
Co-authored-by: Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
The generic unlock() wrote to m_write_locked from every thread
regardless of whether a read or write lock was held. When multiple
threads held concurrent read locks, their unlock() calls would race
on the non-atomic m_write_locked and m_read_locked_with_write_lock
fields.
Split unlock() into unlock_read() and unlock_write() so that read
unlocks never touch the write-lock tracking fields. The RWLockLocker
template dispatches at compile time based on LockMode.
Add a thread-safe deferred_invoke() API on WeakEventLoopReference that
queues work onto the owning thread's event queue and wakes that thread
via EventLoopManager hooks. This avoids calling wake() from foreign
threads during teardown.
Implement current_thread_handle()/wake_thread() in each backend and
track per-thread data so handles are validated before waking:
- Unix: wake via per-thread wake pipe
- Windows: wake via thread wake event
- macOS: wake via stored CFRunLoopRef
- Qt: wake via event target or QEventLoop::wakeUp()
- Android: wake via stored ALooper
Since the event loop has a very specifically scoped lifetime, we can't
ensure that it outlives threads that hold a reference to it without
blocking the thread that owns it. In order to make threads use the
event loop safely, we now have an atomically ref-counted
WeakEventLoopReference class that can be passed off to threads to
safely post events/callbacks to it.
Another possibility was to use an RWLock per event loop that each
thread holds a read lock on, while ~EventLoop() uses a write lock to
block and prevent it being destroyed until all its threads exit.
However, media data providers don't receive a signal to exit due to the
GC heap being intentionally leaked, so the process never actually
exits. It would be possible to specifically drop the reference to
PlaybackManager in HTMLMediaElement in order to make those data
providers die on their own, but that doesn't help prevent this problem
in other cases where it may arise.
The DeferredInvocationContext only existed to satisfy the requirement
in ThreadEventQueue that each event has an EventReceiver. However,
deferred_invoke() was not even using the EventReceiver to call its
callback. Therefore, we don't need to allocate one for every deferred
invocation.
This also prevents WeakPtr::strong_ref() from racing and leaking the
context object when invoking a function across threads.
This method was removed in e015a43b51
However, it was not exactly *unused* as the commit message would say.
This method was the only thing that allowed spin_until to exit when
the event loop was cancelled. This happens normally when IPC connections
are closed, but also when the process is killed.
The logic to properly handle process exit from event loop spins needs to
actually notify the caller that their goal condition was not met though.
That will be handled in a later commit.
Problem:
- Many constructors are defined as `{}` rather than using the ` =
default` compiler-provided constructor.
- Some types provide an implicit conversion operator from `nullptr_t`
instead of requiring the caller to default construct. This violates
the C++ Core Guidelines suggestion to declare single-argument
constructors explicit
(https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#c46-by-default-declare-single-argument-constructors-explicit).
Solution:
- Change default constructors to use the compiler-provided default
constructor.
- Remove implicit conversion operators from `nullptr_t` and change
usage to enforce type consistency without conversion.
This was very obviously racy and would only succeed if we already own
the socket anyway. (And if we do, we can bind to it without unlinking!)
Work towards #4876.
This doesn't solve half of the problems with /tmp/rpc, but this way we
can at least make it sticky instead of having it fully world-writable
and owned by whoever was the first to bind an RPC socket.
Move some more complex globals into a Singleton, which allows it being
used from global destructors. It solves problems where some global
variables, such as HashMaps may already be deleted, triggering crashes
trying to use them.
This allows adding and removing of asynchronous signal handlers while
executing signal handlers, even if it is for the same signal that is
being handled right now.
This implements a number of changes related to time:
* If a HPET is present, it is now used only as a system timer, unless
the Local APIC timer is used (in which case the HPET timer will not
trigger any interrupts at all).
* If a HPET is present, the current time can now be as accurate as the
chip can be, independently from the system timer. We now query the
HPET main counter for the current time in CPU #0's system timer
interrupt, and use that as a base line. If a high precision time is
queried, that base line is used in combination with quering the HPET
timer directly, which should give a much more accurate time stamp at
the expense of more overhead. For faster time stamps, the more coarse
value based on the last interrupt will be returned. This also means
that any missed interrupts should not cause the time to drift.
* The default system interrupt rate is reduced to about 250 per second.
* Fix calculation of Thread CPU usage by using the amount of ticks they
used rather than the number of times a context switch happened.
* Implement CLOCK_REALTIME_COARSE and CLOCK_MONOTONIC_COARSE and use it
for most cases where precise timestamps are not needed.
This makes most operations thread safe, especially so that they
can safely be used in the Kernel. This includes obtaining a strong
reference from a weak reference, which now requires an explicit
call to WeakPtr::strong_ref(). Another major change is that
Weakable::make_weak_ref() may require the explicit target type.
Previously we used reinterpret_cast in WeakPtr, assuming that it
can be properly converted. But WeakPtr does not necessarily have
the knowledge to be able to do this. Instead, we now ask the class
itself to deliver a WeakPtr to the type that we want.
Also, WeakLink is no longer specific to a target type. The reason
for this is that we want to be able to safely convert e.g. WeakPtr<T>
to WeakPtr<U>, and before this we just reinterpret_cast the internal
WeakLink<T> to WeakLink<U>, which is a bold assumption that it would
actually produce the correct code. Instead, WeakLink now operates
on just a raw pointer and we only make those constructors/operators
available if we can verify that it can be safely cast.
In order to guarantee thread safety, we now use the least significant
bit in the pointer for locking purposes. This also means that only
properly aligned pointers can be used.
- Parsing invalid JSON no longer asserts
Instead of asserting when coming across malformed JSON,
JsonParser::parse now returns an Optional<JsonValue>.
- Disallow trailing commas in JSON objects and arrays
- No longer parse 'undefined', as that is a purely JS thing
- No longer allow non-whitespace after anything consumed by the initial
parse() call. Examples of things that were valid and no longer are:
- undefineddfz
- {"foo": 1}abcd
- [1,2,3]4
- JsonObject.for_each_member now iterates in original insertion order
This fixes an issue where continuously posting new events to the queue
would keep the event loop saturated, causing it to ignore notifiers.
Since notifiers are part of the big select(), we always have to call
wait_for_events() even if there are pending events. We're already smart
enough to select() without a timeout if we already have pending events.
The event that triggered the exit from an inner event loop would always
get re-delivered in the outer event loop due to a silly off-by-one
mistake when transferring pending events between loops.
Add a SetInspectedObject call that tells us which Core::Object a remote
client is currently looking it. Objects get notified when they gain
their first inspector, and when they lose their last one.