summaryrefslogtreecommitdiff
path: root/Kernel/Thread.cpp
AgeCommit message (Collapse)Author
2020-01-27Kernel: Expose the signal that stopped a thread via sys$waitpid()Andreas Kling
2020-01-27Kernel: Remove ancient hack that put the current PID in TSS.SS2Andreas Kling
While I was bringing up multitasking, I put the current PID in the SS2 (ring 2 stack segment) slot of the TSS. This was so I could see which PID was currently running when just inspecting the CPU state.
2020-01-27Kernel: Simplify kernel thread stack allocationAndreas Kling
We had two identical code paths doing this for some reason.
2020-01-21Kernel: Tidy up debug logging a little bitAndreas Kling
When using dbg() in the kernel, the output is automatically prefixed with [Process(PID:TID)]. This makes it a lot easier to understand which thread is generating the output. This patch also cleans up some common logging messages and removes the now-unnecessary "dbg() << *current << ..." pattern.
2020-01-20Kernel: Use the templated copy_to/from_user() in more placesAndreas Kling
These ensure that the "to" and "from" pointers have the same type, and also that we copy the correct number of bytes.
2020-01-20Kernel: Remove some unnecessary casts to uintptr_tAndreas Kling
VirtualAddress is constructible from uintptr_t and const void*. PhysicalAddress is constructible from uintptr_t but not const void*.
2020-01-20Use uintptr_t instead of u32 when storing pointers as integersAndreas Kling
uintptr_t is 32-bit or 64-bit depending on the target platform. This will help us write pointer size agnostic code so that when the day comes that we want to do a 64-bit port, we'll be in better shape.
2020-01-19Kernel: Limit Thread::raw_backtrace() to the max profiler stack sizeAndreas Kling
Let's avoid walking overly long stacks here, since kmalloc() is finite.
2020-01-19Kernel: Use copy_from_user() when appropriate during thread backtracingAndreas Kling
2020-01-18Meta: Add license header to source filesAndreas Kling
As suggested by Joshua, this commit adds the 2-clause BSD license as a comment block to the top of every source file. For the first pass, I've just added myself for simplicity. I encourage everyone to add themselves as copyright holders of any file they've added or modified in some significant way. If I've added myself in error somewhere, feel free to replace it with the appropriate copyright holder instead. Going forward, all new source files should include a license header.
2020-01-13Kernel: Allow unlocking a held Lock with interrupts disabledAndreas Kling
This is needed to eliminate a race in Thread::wait_on() where we'd otherwise have to wait until after unlocking the process lock before we can disable interrupts.
2020-01-12Kernel: Fix Lock racing to the WaitQueueAndreas Kling
There was a time window between releasing Lock::m_lock and calling into the lock's WaitQueue where someone else could take m_lock and bring two threads into a deadlock situation. Fix this issue by holding Lock::m_lock until interrupts are disabled by either Thread::wait_on() or WaitQueue::wake_one().
2020-01-12Kernel: Keep SMAP protection enabled in Thread::backtrace_impl()Andreas Kling
2020-01-12Kernel: Fix busted backtraces when a thread backtraces itselfAndreas Kling
When the current thread is backtracing itself, we now start walking the stack from the current EBP register value, instead of the TSS one. Now SystemMonitor always appears to be running Thread::backtrace() when sampled, which makes perfect sense. :^)
2020-01-10Kernel: Fix kernel null deref on process crash during join_thread()Andreas Kling
The join_thread() syscall is not supposed to be interruptible by signals, but it was. And since the process death mechanism piggybacked on signal interrupts, it was possible to interrupt a pthread_join() by killing the process that was doing it, leading to confusing due to some assumptions being made by Thread::finalize() for threads that have a pending joiner. This patch fixes the issue by making "interrupted by death" a distinct block result separate from "interrupted by signal". Then we handle that state in join_thread() and tidy things up so that thread finalization doesn't get confused by the pending joiner being gone. Test: Tests/Kernel/null-deref-crash-during-pthread_join.cpp
2020-01-09Kernel: Rename {ss,esp}_if_crossRing to userspace_{ss,esp}Andreas Kling
These were always so awkwardly named.
2020-01-09Kernel: Remove unused variable Thread::m_userspace_stack_regionAndreas Kling
2020-01-05Kernel: Fix SMAP violation in thread signal dispatchAndreas Kling
2020-01-05Kernel: Start implementing x86 SMAP supportAndreas Kling
Supervisor Mode Access Prevention (SMAP) is an x86 CPU feature that prevents the kernel from accessing userspace memory. With SMAP enabled, trying to read/write a userspace memory address while in the kernel will now generate a page fault. Since it's sometimes necessary to read/write userspace memory, there are two new instructions that quickly switch the protection on/off: STAC (disables protection) and CLAC (enables protection.) These are exposed in kernel code via the stac() and clac() helpers. There's also a SmapDisabler RAII object that can be used to ensure that you don't forget to re-enable protection before returning to userspace code. THis patch also adds copy_to_user(), copy_from_user() and memset_user() which are the "correct" way of doing things. These functions allow us to briefly disable protection for a specific purpose, and then turn it back on immediately after it's done. Going forward all kernel code should be moved to using these and all uses of SmapDisabler are to be considered FIXME's. Note that we're not realizing the full potential of this feature since I've used SmapDisabler quite liberally in this initial bring-up patch.
2020-01-04Kernel: Use Thread::from_tid() in more placesAndreas Kling
2020-01-02Kernel: Mask kernel addresses in backtraces and profilesAndreas Kling
Addresses outside the userspace virtual range will now show up as 0xdeadc0de in backtraces and profiles generated by unprivileged users.
2020-01-01Kernel: Prevent executing I/O instructions in userspaceAndreas Kling
All threads were running with iomapbase=0 in their TSS, which the CPU interprets as "there's an I/O permission bitmap starting at offset 0 into my TSS". Because of that, any bits that were 1 inside the TSS would allow the thread to execute I/O instructions on the port with that bit index. Fix this by always setting the iomapbase to sizeof(TSS32), and also setting the TSS descriptor's limit to sizeof(TSS32), effectively making the I/O permissions bitmap zero-length. This should make it no longer possible to do I/O from userspace. :^)
2020-01-01Kernel: Switch to eagerly restoring x86 FPU state on context switchAndreas Kling
Lazy FPU restore is well known to be vulnerable to timing attacks, and eager restore is a lot simpler anyway, so let's just do it eagerly.
2019-12-31Kernel: Remove some unnecessary leaking of kernel pointers into dmesgAndreas Kling
There's a lot more of this and we need to stop printing kernel pointers anywhere but the debug console.
2019-12-30Kernel: Add a basic thread boosting mechanismAndreas Kling
This patch introduces a syscall: int set_thread_boost(int tid, int amount) You can use this to add a permanent boost value to the effective thread priority of any thread with your UID (or any thread in the system if you are the superuser.) This is quite crude, but opens up some interesting opportunities. :^)
2019-12-30Kernel: Refactor scheduler to use dynamic thread prioritiesAndreas Kling
Threads now have numeric priorities with a base priority in the 1-99 range. Whenever a runnable thread is *not* scheduled, its effective priority is incremented by 1. This is tracked in Thread::m_extra_priority. The effective priority of a thread is m_priority + m_extra_priority. When a runnable thread *is* scheduled, its m_extra_priority is reset to zero and the effective priority returns to base. This means that lower-priority threads will always eventually get scheduled to run, once its effective priority becomes high enough to exceed the base priority of threads "above" it. The previous values for ThreadPriority (Low, Normal and High) are now replaced as follows: Low -> 10 Normal -> 30 High -> 50 In other words, it will take 20 ticks for a "Low" priority thread to get to "Normal" effective priority, and another 20 to reach "High". This is not perfect, and I've used some quite naive data structures, but I think the mechanism will allow us to build various new and interesting optimizations, and we can figure out better data structures later on. :^)
2019-12-25Kernel: Make kernel memory regions be non-executable by defaultAndreas Kling
From now on, you'll have to request executable memory specifically if you want some.
2019-12-25Kernel: Enable PAE (Physical Address Extension)Andreas Kling
Introduce one more (CPU) indirection layer in the paging code: the page directory pointer table (PDPT). Each PageDirectory now has 4 separate PageDirectoryEntry arrays, governing 1 GB of VM each. A really neat side-effect of this is that we can now share the physical page containing the >=3GB kernel-only address space metadata between all processes, instead of lazily cloning it on page faults. This will give us access to the NX (No eXecute) bit, allowing us to prevent execution of memory that's not supposed to be executed.
2019-12-24Kernel: Fix debug message and kernel stack region names in thread setupConrad Pankoff
2019-12-24Kernel: Mark kernel stack regions as... stack regionsConrad Pankoff
2019-12-24Kernel: Move ring0 stacks out of kmalloc_eternalConrad Pankoff
This allows us to use all the same fun memory protection features as the rest of the system for ring0 processes. Previously a ring0 process could over- or underrun its stack and nobody cared, since kmalloc_eternal is the wild west of memory.
2019-12-24Kernel: Add a size argument to validate_read_from_kernelConrad Pankoff
2019-12-22Kernel: Unlock the Process when exit()ingAndreas Kling
If there are more threads in a process when exit()ing, we need to give them a chance to unwind any kernel stacks. This means we have to unlock the process lock before giving control to the scheduler. Fixes #891 (together with all of the other "no more main thread" work.)
2019-12-22Kernel: Use IntrusiveList to make WaitQueue allocation-free :^)Andreas Kling
2019-12-22Kernel: Make TID's be unique PID'sAndreas Kling
This is a little strange, but it's how I understand things should work. The first thread in a new process now has TID == PID. Additional threads subsequently spawned in that process all have unique TID's generated by the PID allocator. TIDs are now globally unique.
2019-12-22Kernel: Get rid of "main thread" conceptAndreas Kling
The idea of all processes reliably having a main thread was nice in some ways, but cumbersome in others. More importantly, it didn't match up with POSIX thread semantics, so let's move away from it. This thread gets rid of Process::main_thread() and you now we just have a bunch of Thread objects floating around each Process. When the finalizer nukes the last Thread in a Process, it will also tear down the Process. There's a bunch of more things to fix around this, but this is where we get started :^)
2019-12-18Kernel: Fix intermittent assertion failure in sys$exec()Andreas Kling
While setting up the main thread stack for a new process, we'd incur some zero-fill page faults. This was to be expected, since we allocate a huge stack but lazily populate it with physical pages. The problem is that page fault handlers may enable interrupts in order to grab a VMObject lock (or to page in from an inode.) During exec(), a process is reorganizing itself and will be in a very unrunnable state if the scheduler should interrupt it and then later ask it to run again. Which is exactly what happens if the process gets pre-empted while the new stack's zero-fill page fault grabs the lock. This patch fixes the issue by creating new main thread stacks before disabling interrupts and going into the critical part of exec().
2019-12-15Kernel: Fix get_register_dump_from_stack() after IRQ entry changesAndreas Kling
I had to change the layout of RegisterDump a little bit to make the new IRQ entry points work. This broke get_register_dump_from_stack() which was expecting the RegisterDump to be badly aligned due to a goofy extra 16 bits which are no longer there.
2019-12-11Kernel: Implement a simple process time profilerAndreas Kling
The kernel now supports basic profiling of all the threads in a process by calling profiling_enable(pid_t). You finish the profiling by calling profiling_disable(pid_t). This all works by recording thread stacks when the timer interrupt fires and the current thread is in a process being profiled. Note that symbolication is deferred until profiling_disable() to avoid adding more noise than necessary to the profile. A simple "/bin/profile" command is included here that can be used to start/stop profiling like so: $ profile 10 on ... wait ... $ profile 10 off After a profile has been recorded, it can be fetched in /proc/profile There are various limits (or "bugs") on this mechanism at the moment: - Only one process can be profiled at a time. - We allocate 8MB for the samples, if you use more space, things will not work, and probably break a bit. - Things will probably fall apart if the profiled process dies during profiling, or while extracing /proc/profile
2019-12-08Kernel: Allow setting thread namesAndrew Kaster
The main thread of each kernel/user process will take the name of the process. Extra threads will get a fancy new name "ProcessName[<tid>]". Thread backtraces now list the thread name in addtion to tid. Add the thread name to /proc/all (should it get its own proc file?). Add two new syscalls, set_thread_name and get_thread_name.
2019-12-01Kernel: Use a WaitQueue to implement finalizer wakeupAndreas Kling
This gets rid of the special "Lurking" thread state and replaces it with a generic WaitQueue :^)
2019-12-01Kernel: Use a dedicated thread state for wait-queued threadsAndreas Kling
Instead of using the generic block mechanism, wait-queued threads now go into the special Queued state. This fixes an issue where signal dispatch would unblock a wait-queued thread (because signal dispatch unblocks blocked threads) and cause confusion since the thread only expected to be awoken by the queue.
2019-12-01Kernel: Add a WaitQueue for Thread queueing/waking and use it for LockAndreas Kling
The kernel's Lock class now uses a proper wait queue internally instead of just having everyone wake up regularly to try to acquire the lock. We also keep the donation mechanism, so that whenever someone tries to take the lock and fails, that thread donates the remainder of its timeslice to the current lock holder. After unlocking a Lock, the unlocking thread calls WaitQueue::wake_one, which unblocks the next thread in queue.
2019-11-29Kernel: Demangle kernel C++ symbols correctly againAndreas Kling
I broke this while implementing module linking. Also move the actual demangling work to AK, in AK::demangle(const char*)
2019-11-17Kernel+LibPthread+LibC: Create secondary thread stacks in userspaceAndreas Kling
Have pthread_create() allocate a stack and passing it to the kernel instead of this work happening in the kernel. The more of this we can do in userspace, the better. This patch also unexposes the raw create_thread() and exit_thread() syscalls since they are now only used by LibPthread anyway.
2019-11-17Kernel: Implement some basic stack pointer validationAndreas Kling
VM regions can now be marked as stack regions, which is then validated on syscall, and on page fault. If a thread is caught with its stack pointer pointing into anything that's *not* a Region with its stack bit set, we'll crash the whole process with SIGSTKFLT. Userspace must now allocate custom stacks by using mmap() with the new MAP_STACK flag. This mechanism was first introduced in OpenBSD, and now we have it too, yay! :^)
2019-11-16Kernel: Release the big process lock while yielding in sys$yield()Andreas Kling
Otherwise, a thread calling sched_yield() will prevent other threads in that process from entering the kernel.
2019-11-14Kernel: Move Thread::m_joinee_exit_value into the JoinBlockerAndreas Kling
There's no need for this to be a permanent Thread member. Just use a reference in the JoinBlocker instead.
2019-11-14Kernel+LibPthread: Implement pthread_join()Andreas Kling
It's now possible to block until another thread in the same process has exited. We can also retrieve its exit value, which is whatever value it passed to pthread_exit(). :^)
2019-11-14Kernel: Unwind kernel stacks before dyingSergey Bugaev
While executing in the kernel, a thread can acquire various resources that need cleanup, such as locks and references to RefCounted objects. This cleanup normally happens on the exit path, such as in destructors for various RAII guards. But we weren't calling those exit paths when killing threads that have been executing in the kernel, such as threads blocked on reading or sleeping, thus causing leaks. This commit changes how killing threads works. Now, instead of killing a thread directly, one is supposed to call thread->set_should_die(), which will unblock it and make it unwind the stack if it is blocked in the kernel. Then, just before returning to the userspace, the thread will automatically die.