Age | Commit message (Collapse) | Author |
|
The "stddbg" stream was a cute idea but we never ended up using it in
practice, so let's simplify this and implement userspace dbgprintf() on top
of a simple dbgputch() syscall instead.
This makes debugging LibC startup a little bit easier. :^)
|
|
|
|
Restructure the makefile a little so it only builds objects once, and
then run them on make clean.
This is a little slower (since we're relinking tests each makeall), but
it also ensures that it will work.
|
|
The debug output was basically dominated by Ext2FS spam.
|
|
Add a trivial CSafeSyscall template that calls a callback until it stops
returning EINTR, and use it everywhere we use select() now.
Thanks to Andreas for the suggestion of using a template parameter for
the syscall function to invoke.
|
|
Check for EINTR before doing anything with the passed sets, otherwise we
zero them out which means a re-call with the same sets won't work.
|
|
Caught by valgrind's uninitialized access checks on the Vector unit test.
Yay for finding bugs with valgrind on the unit tests! :^)
|
|
Same as the RefPtr issue I just fixed. This makes it possible to assign a
NonnullRefPtr<Derived>&& to a NonnullRefPtr<Base>.
|
|
With the presence of signal handlers, it is possible that a thread might
be blocked multiple times. Picture for instance a signal handler using
read(), or wait() while the thread is already blocked elsewhere before
the handler is invoked.
To fix this, we turn m_blocker into a chain of handlers. Each block()
call now prepends to the list, and unblocking will only consider the
most recent (first) blocker in the chain.
Fixes #309
|
|
Makes checking for leaks more straightforward
|
|
To be more consistent with the rest of the codebase
|
|
Otherwise it's not possible to assign a RefPtr<Derived>&& to a RefPtr<Base>.
|
|
It's good to verify that complex objects can be moved nicely by Vector.
|
|
|
|
We were not actually running any of the unit tests, only getting a pointer
to them. Thankfully they all pass, even after we start running them. :^)
|
|
This makes it much harder to screw with an application while it's showing
a modal window, and matches what some other systems are doing. :^)
|
|
Added some FIXME's about correctness issues in nested event loop exiting.
|
|
This is very simple but already very useful. Now you're able to call to
dump_backtrace() from anywhere userspace to get a nice symbolicated
backtrace in the debugger output. :^)
|
|
Fixes #352.
|
|
Fixes #308.
|
|
It was annoying to always write set_preferred_size({ width, height }). :^)
|
|
|
|
Now you can ask for e.g Size::primary_size_for_orientation(Orientation).
|
|
You now have to pass an Orientation to the GSlider constructor. It's not
possible to change the orientation after construction.
Added some vertical GSliders to the WidgetGallery demo for testing. :^)
|
|
These are useful when doing widgets that can be switched between vertical
and horizontal mode, such as GSlider. The idea is that instead of using
"x" and "y" directly, you use the "primary" and "secondary" offset/size
for the Orientation you're configured in.
|
|
|
|
The only two places we set m_blocker now are Thread::set_state(), and
Thread::block(). set_state is mostly just an issue of clarity: we don't
want to end up with state() != Blocked with an m_blocker, because that's
weird. It's also possible: if we yield, someone else may set_state() us.
We also now set_state() and set m_blocker under lock in block(), rather
than unlocking which might allow someone else to mess with our internals
while we're in the process of trying to block.
This seems to fix sending STOP & CONT causing a panic.
My guess as to what was happening is this:
thread A blocks in select(): Blocking & m_blocker != nullptr
thread B sends SIGSTOP: Stopped & m_blocker != nullptr
thread B sends SIGCONT: we continue execution. Runnable & m_blocker != nullptr
thread A tries to block in select() again:
* sets m_blocker
* unlocks (in block_helper)
* someone else tries to unblock us? maybe from the old m_blocker? unclear -- clears m_blocker
* sets Blocked (while unlocked!)
So, thread A is left with state Blocked & m_blocker == nullptr, leading
to the scheduler assert (m_blocker != nullptr) failing.
Long story short, let's do all our data management with the lock _held_.
|
|
When exiting a nested event loop, we prepend any unprocessed events to the
outer loop's event queue.
|
|
Also included a good boy unit test.
|
|
|
|
Block will yield for us, so there's no reason to return control to the
scheduler immediately after we just blocked.
|
|
uses it)
Also do this more like other blockers, don't call yield ourselves, as
block will do that for us.
|
|
And use this to return EINTR in various places; some of which we were
not handling properly before.
This might expose a few bugs in userspace, but should be more compatible
with other POSIX systems, and is certainly a little cleaner.
|
|
I had the right cause of the SharedBuffer leak, but goofed the fix by
desynching the per-pid refcount and the global refcount.
Fix that, and add a generous sprinkle of asserts to make sure the two
stay in sync.
Fixes #341
(... for real this time)
|
|
Make LineEditor::get_line() responsible for printing the prompt. That way
we can re-prompt after clearing the screen on ^L.
This makes the Serenity Terminal feel a little bit more like home :^)
|
|
It's a very bad idea to increment the refcount on behalf of another
process. That process may (for either benign or evil reasons) not
reference the SharedBuffer, and then we'll be stuck with loads of
SharedBuffers until we OOM.
Instead, increment the refcount when the buffer is mapped. That way, a
buffer is only kept if *someone* has explicitly requested it via
get_shared_buffer.
Fixes #341
|
|
Generate a special page containing the "return from signal" trampoline code
on startup and then route signalled threads to it. This avoids a page
allocation in every process that ever receives a signal.
|
|
|
|
Region now has is_user_accessible(), which informs the memory manager how
to map these pages. Previously, we were just passing a "bool user_allowed"
to various functions and I'm not at all sure that any of that was correct.
All the Region constructors are now hidden, and you must go through one of
these helpers to construct a region:
- Region::create_user_accessible(...)
- Region::create_kernel_only(...)
That ensures that we don't accidentally create a Region without specifying
user accessibility. :^)
|
|
Accidentally forgot to check the state parameter, which made this rather useless.
Bug found, and cause identified by Andreas
|
|
And use it in the scheduler.
IntrusiveList is similar to InlineLinkedList, except that rather than
making assertions about the type (and requiring inheritance), it
provides an IntrusiveListNode type that can be used to put an instance
into many different lists at once.
As a proof of concept, port the scheduler over to use it. The only
downside here is that the "list" global needs to know the position of
the IntrusiveListNode member, so we have to position things a little
awkwardly to make that happen. We also move the runnable lists to
Thread, to avoid having to publicize the node.
|
|
Nobody should ever construct one of these directly.
|
|
Committing some things my hands did while browsing through this code.
- Mark all leaf classes "final".
- FileDescriptionBlocker now stores a NonnullRefPtr<FileDescription>.
- FileDescriptionBlocker::blocked_description() now returns a reference.
- ConditionBlocker takes a Function&&.
|
|
|
|
|
|
than rewriting them
This avoids exposing the runnable lists to Process.
|
|
This way a caller can abort the for_each early if they want.
|
|
Following the discussion in #334, shutdown must also have root-only
run permissions.
|
|
|
|
New API should be used always :)
|