Commit graph

1298 commits

Author SHA1 Message Date
Andreas Kling
5e01ebfc56 Kernel: Clean up thread stacks when a thread dies
We were forgetting where we put the userspace thread stacks, so added a
member called Thread::m_userspace_thread_stack to keep track of it.

Then, in ~Thread(), we now deallocate the userspace, kernel and signal
stacks (if present.)

Out of curiosity, the "init_stage2" process doesn't have a kernel stack
which I found surprising. :^)
2019-08-01 20:17:12 +02:00
Andreas Kling
3ad6ae1842 Kernel: Delete non-main threads immediately after finalizing them
Previously we would wait until the whole process died before actually
deleting its threads.
2019-08-01 20:01:23 +02:00
Andreas Kling
55d6efd485 Scheduler: Fix bitrotted SCHEDULER_RUNNABLE_DEBUG code
The runnable lists have moved from Thread to Scheduler.
2019-08-01 20:00:56 +02:00
Andreas Kling
09cd3a7a07 Scheduler: Fix deadlock when first scheduling candidate being inspected
Somewhat reproducible by opening ProcessManager and trying to view the
stacks for WindowServer.

Regressed in 53262cd08b.
2019-08-01 19:33:36 +02:00
Andreas Kling
8b34b1222b ProcFS: Make some use of Vector::empend(). 2019-08-01 16:34:02 +02:00
Andreas Kling
4afafeae50 Ext2FS: Make some use of Vector::empend(). 2019-08-01 16:31:05 +02:00
Andreas Kling
cbfa211988 ProcFS: Align the buffer used for the CPUID brand string.
I'm not sure if this actually matters, but it won't hurt anyone to use
a 32-bit aligned buffer here.

Found by PVS-Studio.
2019-08-01 11:38:15 +02:00
Andreas Kling
1a13145cb3 Kernel: Remove unnecessary null check in Process::fork()
Found by PVS-Studio.
2019-08-01 11:15:48 +02:00
Andreas Kling
be4d33fb2c Kernel+LibC: A lot of the signal handling code was off-by-one.
There is no signal 0. The valid ones are 1 (SIGHUP) through 31 (SIGSYS)
Found by PVS-Studio.
2019-08-01 11:03:48 +02:00
Andreas Kling
ecb1b93d53 Ext2FS: Fix fetching of the major/minor device numbers for st_rdev.
This is how it seems to work:

- If ext2_inode.i_blocks[0] is non-zero, it contains the major/minor.
- Otherwise, it's in ext2_inode.i_blocks[1].
2019-07-31 17:24:54 +02:00
Robin Burchell
246c011497 Kernel: Port /proc/PID/fds to JSON 2019-07-31 10:48:53 +02:00
Conrad Pankoff
973c2d9bfd Kernel: fix typo regarding floppy drives in init_stage2 2019-07-30 09:16:47 +02:00
Andreas Kling
2feddc58bb Kernel: Oops, forgot to add Lock.cpp. 2019-07-29 12:00:14 +02:00
Andreas Kling
57c29491a3 Kernel+AK: Remove AK/StdLibExtras.cpp, moving kernel stuff to Kernel/.
We had some kernel-specific gizmos in AK that should really just be in the
Kernel subdirectory instead. The only thing remaining after moving those
was mmx_memcpy() which I moved to the ARCH(i386)-specific section of
LibC/string.cpp.
2019-07-29 11:58:44 +02:00
Andreas Kling
c59fdcc021 Kernel: Move Lock code out-of-line.
It's so big and chunky anyway, it's silly to expand it everywhere.
This makes it a lot easier to read function disassembly dumps.
2019-07-29 11:19:04 +02:00
Andreas Kling
5ded77df39 Kernel+ProcessManager: Let processes have an icon and show it in the table.
Processes can now have an icon assigned, which is essentially a 16x16 RGBA32
bitmap exposed as a shared buffer ID.

You set the icon ID by calling set_process_icon(int) and the icon ID will be
exposed through /proc/all.

To make this work, I added a mechanism for making shared buffers globally
accessible. For safety reasons, each app seals the icon buffer before making
it global.

Right now the first call to GWindow::set_icon() is what determines the
process icon. We'll probably change this in the future. :^)
2019-07-29 07:26:01 +02:00
DrewStratford
608fee9bff Kernel: Add bounds checking to recognized_symbols in dump_backtrace_impl (#372)
This adds a bounds check to the loop that writes to the buffer
'recognized_symbols'. This prevents buffer overflows in the
case when a programs backtrace is particularly large.

Fixes #371.
2019-07-28 20:02:22 +02:00
Jesse
59e122f8ba Kernel: Expand PATA driver to support multiple hard drives (#365)
The previous implementation of the PIIX3/4 PATA/IDE channel driver only
supported a single drive, as the object model was wrong (the channel
inherits the IRQ, not the disk drive itself). This fixes it by 'attaching'
two `PATADiskDevices` to a `PATAChannel`, which makes more sense.

The reading/writing code is presented as is, which violates the spec
outlined by Seagate in the linked datasheet. That spec is rather old,
so it might not be 100% up to date, though may cause issues on real
hardware, so until we can actually test it, this will suffice.
2019-07-28 15:44:01 +02:00
Andreas Kling
52a5e34902 Kernel: Convert /proc/PID/vm to JSON. 2019-07-28 11:37:50 +02:00
Andreas Kling
63619b9f7c Kernel: Disallow access to shared buffers we're not allowed to access.
Unless we're on the share list, make all shared buffer related syscalls
return EPERM.
2019-07-28 07:13:38 +02:00
Andreas Kling
a79d8d8ae5 Kernel: Add (expensive) but valuable userspace symbols to stacks.
This is expensive because we have to page in the entire executable for every
process up front for this to work. This is due to the page fault code not
being strong enough to run while another process is active.

Note that we already had userspace symbols in *crash* stacks. This patch
adds them generally, so they show up in /proc, Process Manager, etc.

There's room for improvement here, but the debugging benefits way overshadow
the performance penalty right now. :^)
2019-07-27 12:02:56 +02:00
Andreas Kling
4316fa8123 Kernel: Dump backtrace to debugger for DefaultSignalAction::DumpCore.
This makes assertion failures generate backtraces again. Sorry to everyone
who suffered from the lack of backtraces lately. :^)

We share code with the /proc/PID/stack implementation. You can now get the
current backtrace for a Thread via Thread::backtrace(), and all the traces
for a Process via Process::backtrace().
2019-07-25 21:02:19 +02:00
Andreas Kling
1d0b464618 AK: Make HashMap::get(Key) return an Optional<Value>.
This allows HashMap::get() to be used for value types that cannot be default
constructed (e.g NonnullOwnPtr.)
2019-07-24 10:25:43 +02:00
Andreas Kling
394168c0ca Kernel: Convert Vector<OwnPtr> to NonnullOwnPtrVector. 2019-07-24 09:15:33 +02:00
Andreas Kling
93489fbc4c Convert HashMap<Key, OwnPtr<T>> to HashMap<Key, NonnullOwnPtr<T>>.
In every case I found, we never wanted to support null entry values.
With NonnullOwnPtr, we can encode that at the type level. :^)
2019-07-24 08:42:55 +02:00
Andreas Kling
1f8f739ea2 Kernel: Simplify PhysicalPage construction.
There was some leftover cruft from the times when PhysicalPage was allocated
using different allocators depending on lifetime.
2019-07-24 06:29:47 +02:00
Andreas Kling
c8e2bb5605 Kernel: Add a mechanism for listening for changes to an inode.
The syscall is quite simple:

    int watch_file(const char* path, int path_length);

It returns a file descriptor referring to a "InodeWatcher" object in the
kernel. It becomes readable whenever something changes about the inode.

Currently this is implemented by hooking the "metadata dirty bit" in
Inode which isn't perfect, but it's a start. :^)
2019-07-22 20:01:11 +02:00
Andreas Kling
a9adf4c95b DevPtsFS: Use String::number() in a place where it makes sense. 2019-07-22 10:42:34 +02:00
Robin Burchell
342f7a6b0f Move runnable/non-runnable list control entirely over to Scheduler
This way, we can change how the scheduler works without having to change Thread too.
2019-07-22 09:42:39 +02:00
Andreas Kling
af81645a2a Kernel+LibC: Add a dbgputstr() syscall for sending strings to debug output.
This is very handy for the DebugLogStream implementation, among others. :^)
2019-07-21 21:43:37 +02:00
Andreas Kling
38b13f1508 Kernel: Remove bitrotted "spawn stress" code.
This was something I used during early kernel development to spam creation
of new processes to see if the kernel could handle it.
2019-07-21 19:51:32 +02:00
Andreas Kling
3fce2fb205 Kernel+LibC: Add a dbgputch() syscall and use it for userspace dbgprintf().
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. :^)
2019-07-21 19:45:31 +02:00
Robin Burchell
a3213659dd AK: Run host tests on make
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.
2019-07-21 18:48:44 +02:00
Andreas Kling
3b588b7dc0 Ext2FS: Put most debug logging behind EXT2_DEBUG.
The debug output was basically dominated by Ext2FS spam.
2019-07-21 18:38:14 +02:00
Robin Burchell
a1eff3daba Process: Fix select/poll EINTR
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.
2019-07-21 14:27:14 +02:00
Robin Burchell
dea7f937bf Scheduler: Allow reentry into block()
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
2019-07-21 12:42:22 +02:00
Andreas Kling
d2b521f0ab Kernel+LibC: Add a dump_backtrace() syscall.
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. :^)
2019-07-21 09:59:17 +02:00
Robin Burchell
d48c73b10a Thread: Cleanup m_blocker handling
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_.
2019-07-20 19:31:52 +02:00
Robin Burchell
98929ba715 Finalizer: Don't double-yield
Block will yield for us, so there's no reason to return control to the
scheduler immediately after we just blocked.
2019-07-20 12:15:24 +02:00
Robin Burchell
96de90ceef Net: Merge Thread::wait_for_connect into LocalSocket (as the only place that uses it)
Also do this more like other blockers, don't call yield ourselves, as
block will do that for us.
2019-07-20 12:15:24 +02:00
Robin Burchell
833d444cd8 Thread: Return a result from block() indicating why the block terminated
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.
2019-07-20 12:15:24 +02:00
Robin Burchell
56217c7432 SharedBuffer: Amend commit 2d4d465206
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)
2019-07-20 12:15:11 +02:00
Robin Burchell
2d4d465206 SharedBuffer: Fix a denial of service
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
2019-07-19 19:06:28 +02:00
Andreas Kling
f8beb0f665 Kernel: Share the "return to ring 0/3 from signal" trampolines globally.
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.
2019-07-19 17:01:16 +02:00
Andreas Kling
fdf931cfce Kernel: Remove accidental use of removed Region::set_user_accessible(). 2019-07-19 16:22:09 +02:00
Andreas Kling
5b2447a27b Kernel: Track user accessibility per Region.
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. :^)
2019-07-19 16:11:52 +02:00
Robin Burchell
4547a301c4 Thread: Fix a regression introduced in 80a6df9022
Accidentally forgot to check the state parameter, which made this rather useless.

Bug found, and cause identified by Andreas
2019-07-19 16:06:51 +02:00
Robin Burchell
53262cd08b AK: Introduce IntrusiveList
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.
2019-07-19 15:42:30 +02:00
Andreas Kling
218069f421 Kernel: Make the Thread::FileDescriptionBlocker constructor protected.
Nobody should ever construct one of these directly.
2019-07-19 13:32:56 +02:00
Andreas Kling
705cd2491c Kernel: Some small refinements to the thread blockers.
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&&.
2019-07-19 13:19:47 +02:00