Commit Graph

285 Commits

Author SHA1 Message Date
Andreas Kling
48f7c28a5c Kernel: Replace "current" with Thread::current and Process::current
Suggested by Sergey. The currently running Thread and Process are now
Thread::current and Process::current respectively. :^)
2020-02-17 15:04:27 +01:00
Andreas Kling
a356e48150 Kernel: Move all code into the Kernel namespace 2020-02-16 01:27:42 +01:00
Andreas Kling
0341ddc5eb Kernel: Rename RegisterDump => RegisterState 2020-02-16 00:15:37 +01:00
Andreas Kling
1828d9eadd Kernel: Remove some commented-out code in Scheduler::yield() 2020-02-10 20:16:50 +01:00
Andreas Kling
7cf33a8ccb Kernel: Remove outdated FIXME from Scheduler 2020-02-10 20:15:53 +01:00
Andreas Kling
934b1d8a9b Kernel: Finalizer should not go back to sleep if there's more to do
Before putting itself back on the wait queue, the finalizer task will
now check if there's more work to do, and if so, do it first. :^)

This patch also puts a bunch of process/thread debug logging behind
PROCESS_DEBUG and THREAD_DEBUG since it was unbearable to debug this
stuff with all the spam.
2020-02-01 10:56:17 +01:00
Andreas Kling
137a45dff2 Kernel: read()/write() should respect timeouts when used on a sockets
Move timeout management to the ReadBlocker and WriteBlocker classes.
Also get rid of the specialized ReceiveBlocker since it no longer does
anything that ReadBlocker can't do.
2020-01-26 17:54:23 +01:00
Andreas Kling
c3e4387c57 Kernel: Stop flushing GDT/IDT registers all the time 2020-01-18 11:10:44 +01:00
Andreas Kling
94ca55cefd Meta: Add license header to source files
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-18 09:45:54 +01:00
Andreas Kling
8b54ba0d61 Kernel: Dispatch pending signals when returning from a syscall
It was quite easy to put the system into a heavy churn state by doing
e.g "cat /dev/zero".

It was then basically impossible to kill the "cat" process, even with
"kill -9", since signals are only delivered in two conditions:

a) The target thread is blocked in the kernel
b) The target thread is running in userspace

However, since "cat /dev/zero" command spends most of its time actively
running in the kernel, not blocked, the signal dispatch code just kept
postponing actually handling the signal indefinitely.

To fix this, we now check before returning from a syscall if there are
any pending unmasked signals, and if so, we take a dramatic pause by
blocking the current thread, knowing it will immediately be unblocked
by signal dispatch anyway. :^)
2020-01-12 15:04:33 +01:00
Andreas Kling
9e51291aed Kernel: Disable SMAP protection while capturing profile samples 2020-01-12 02:02:29 +01:00
Andreas Kling
17ef5bc0ac Kernel: Rename {ss,esp}_if_crossRing to userspace_{ss,esp}
These were always so awkwardly named.
2020-01-09 18:02:01 +01:00
Andreas Kling
76c20642f0 Kernel: Ignore closed fd's when considering select() unblock
This fixes a null RefPtr deref (which asserts) in the scheduler if a
file descriptor being select()'ed is closed by a second thread while
blocked in select().

Test: Kernel/null-deref-close-during-select.cpp
2020-01-09 12:36:42 +01:00
Andreas Kling
f598bbbb1d Kernel: Prevent executing I/O instructions in userspace
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-01 17:31:41 +01:00
Andreas Kling
fd740829d1 Kernel: Switch to eagerly restoring x86 FPU state on context switch
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.
2020-01-01 16:54:21 +01:00
Andreas Kling
50677bf806 Kernel: Refactor scheduler to use dynamic thread priorities
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-30 18:46:17 +01:00
Conrad Pankoff
115b315375 Kernel: Add kernel-level timer queue (heavily based on @juliusf's work)
PR #591 defines the rationale for kernel-level timers. They're most
immediately useful for TCP retransmission, but will most likely see use
in many other areas as well.
2019-12-27 02:15:45 +01:00
Andreas Kling
abdd5aa08a Kernel: Separate runnable thread queues by priority
This patch introduces three separate thread queues, one for each thread
priority available to userspace (Low, Normal and High.)

Each queue operates in a round-robin fashion, but we now always prefer
to schedule the highest priority thread that currently wants to run.

There are tons of tweaks and improvements that we can and should make
to this mechanism, but I think this is a step in the right direction.

This makes WindowServer significantly more responsive while one of its
clients is burning CPU. :^)
2019-12-27 00:52:30 +01:00
Andreas Kling
95034fdfbd Kernel: Move PC speaker beep timing logic from scheduler to the syscall
I don't know why I put this in the scheduler to begin with.. the caller
can just block until the beeping is finished.
2019-12-26 22:31:26 +01:00
Andreas Kling
16812f0f98 Kernel: Get rid of "main thread" concept
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-22 12:37:58 +01:00
Andreas Kling
77cf607cda Kernel+LibC: Publish a "kernel info page" and use it for gettimeofday()
This patch adds a single "kernel info page" that is mappable read-only
by any process and contains the current time of day.

This is then used to implement a version of gettimeofday() that doesn't
have to make a syscall.

To protect against race condition issues, the info page also has a
serial number which is incremented whenever the kernel updates the
contents of the page. Make sure to verify that the serial number is the
same before and after reading the information you want from the page.
2019-12-15 21:29:26 +01:00
Andreas Kling
b32e961a84 Kernel: Implement a simple process time profiler
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-11 20:36:56 +01:00
Andreas Kling
8bb98aa31b Kernel: Use a WaitQueue to implement finalizer wakeup
This gets rid of the special "Lurking" thread state and replaces it
with a generic WaitQueue :^)
2019-12-01 19:17:17 +01:00
Andreas Kling
5859e16e53 Kernel: Use a dedicated thread state for wait-queued threads
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-01 16:02:58 +01:00
Andreas Kling
f067730f6b Kernel: Add a WaitQueue for Thread queueing/waking and use it for Lock
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-12-01 12:07:43 +01:00
Andreas Kling
cb5021419e Kernel: Move Thread::m_joinee_exit_value into the JoinBlocker
There's no need for this to be a permanent Thread member. Just use a
reference in the JoinBlocker instead.
2019-11-14 21:04:34 +01:00
Andreas Kling
69efa3f630 Kernel+LibPthread: Implement pthread_join()
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-14 20:58:23 +01:00
Andreas Kling
083c5f8b89 Kernel: Rework Process::Priority into ThreadPriority
Scheduling priority is now set at the thread level instead of at the
process level.

This is a step towards allowing processes to set different priorities
for threads. There's no userspace API for that yet, since only the main
thread's priority is affected by sched_setparam().
2019-11-06 16:30:06 +01:00
Drew Stratford
7fc903b97a Kernel: Add exception_code to RegisterDump.
Added the exception_code field to RegisterDump, removing the need
for RegisterDumpWithExceptionCode. To accomplish this, I had to
push a dummy exception code during some interrupt entries to properly
pad out the RegisterDump. Note that we also needed to change some code
in sys$sigreturn to deal with the new RegisterDump layout.
2019-10-07 16:39:47 +02:00
Andreas Kling
c33ac7f170 Kernel: Don't update Thread TSS if scheduler tick reschedules it
If we didn't find anything else that wants to run, we don't need to
update the current thread's TSS since we're just gonna return to the
same thread anyway.
2019-10-02 13:47:44 +02:00
Andreas Kling
e1481dcb42 Kernel: Stop idling after handling an IRQ
If we receive an IRQ while the idle task is running, prevent it from
re-halting the CPU after the IRQ handler returns.

Instead have the idle task yield to the scheduler, so we can see if
the IRQ has unblocked something.
2019-09-14 20:21:10 +02:00
Drew Stratford
b65bedd610 Kernel: Change m_blockers to m_blocker.
Because of the way signals now work there should
not be more than one blocker per thread. This
changes the blocker and thread class to reflect
that.
2019-09-09 08:35:43 +02:00
Andreas Kling
23eafdb8d6 Kernel: waitpid() should unblock and -ECHILD if SIG_IGN reaps child 2019-09-08 14:01:00 +02:00
Andreas Kling
ec6bceaa08 Kernel: Support thread-local storage
This patch adds support for TLS according to the x86 System V ABI.
Each thread gets a thread-specific memory region, and the GS segment
register always points _to a pointer_ to the thread-specific memory.

In other words, to access thread-local variables, userspace programs
start by dereferencing the pointer at [gs:0].

The Process keeps a master copy of the TLS segment that new threads
should use, and when a new thread is created, they get a copy of it.
It's basically whatever the PT_TLS program header in the ELF says.
2019-09-07 15:55:36 +02:00
Conrad Pankoff
bd6d2c0819 Kernel: Use a more detailed state machine for socket setup 2019-08-10 09:07:11 +02:00
Andreas Kling
1f9b8f0e7c Kernel: Don't create Function objects in the scheduling code
Each Function is a heap allocation, so let's make an effort to avoid
doing that during scheduling. Because of header dependencies, I had to
put the runnables iteration helpers in Thread.h, which is a bit meh but
at least this cuts out all the kmalloc() traffic in pick_next().
2019-08-07 20:43:54 +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
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
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
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
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
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
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
Robin Burchell
d092855c72 Scheduler: Remove some raw use of the runnable lists 2019-07-19 13:19:02 +02:00
Robin Burchell
e74dce65e6 Thread: Normalize all for_each constructs to use IterationDecision
This way a caller can abort the for_each early if they want.
2019-07-19 13:19:02 +02:00
Robin Burchell
762333ba95 Kernel: Restore state strings for block states
"Blocking" is not terribly informative, but now that everything is
ported over, we can force the blocker to provide us with a reason.

This does mean that to_string(State) needed to become a member, but
that's OK.
2019-07-19 11:03:22 +02:00
Robin Burchell
b13f1699fc Kernel: Rename Condition state to Blocked now we only have one blocking mechanism :) 2019-07-19 11:03:22 +02:00
Robin Burchell
d2ca91c024 Kernel: Convert BlockedSignal and BlockedLurking to the new Blocker mechanism
The last two of the old block states gone :)
2019-07-19 11:03:22 +02:00
Robin Burchell
750dbe986d Kernel: Avoid allocations for Select vectors by using inline capacity
Good tip by Andreas :)
2019-07-19 11:03:22 +02:00
Robin Burchell
52743f9eec Kernel: Rename ThreadBlocker classes to avoid stutter
Thread::ThreadBlockerFoo is a lot less nice to read than Thread::FooBlocker
2019-07-19 11:03:22 +02:00
Robin Burchell
782e4ee6e1 Kernel: Port wait to ThreadBlocker 2019-07-19 11:03:22 +02:00
Robin Burchell
4f9ae9b970 Kernel: Port select to ThreadBlocker 2019-07-19 11:03:22 +02:00
Robin Burchell
32fcfb79e9 Kernel: Port sleep to ThreadBlocker 2019-07-19 11:03:22 +02:00
Robin Burchell
0c8813e6d9 Kernel: Introduce ThreadBlocker as a way to make unblocking neater :)
And port all the descriptor-based blocks over to it as a proof of concept.
2019-07-19 11:03:22 +02:00
Robin Burchell
4da2521606 Scheduler: Move thread unblocking out of a lambda to help make things more readable
We also use a switch to explicitly make sure we handle all cases properly.
2019-07-18 16:14:09 +02:00
Robin Burchell
f2fdac789c Kernel: Add a new block state for accept() on a blocking socket
Rather than asserting, which really ruins everyone's day.
2019-07-18 10:56:49 +02:00
Robin Burchell
4f94fbc9e1 Kernel: Split SCHEDULER_DEBUG into a new SCHEDULER_RUNNABLE_DEBUG
And use dbgprintf() consistently on a few of the pieces of logging here.

This is useful when trying to track thread switching when you don't
really care about what it's switching _to_.
2019-07-17 14:23:15 +02:00
Andreas Kling
b2e502e533 Kernel: Add Thread::block_until(Condition).
Replace the class-based snooze alarm mechanism with a per-thread callback.
This makes it easy to block the current thread on an arbitrary condition:

    void SomeDevice::wait_for_irq() {
        m_interrupted = false;
        current->block_until([this] { return m_interrupted; });
    }
    void SomeDevice::handle_irq() {
        m_interrupted = true;
    }

Use this in the SB16 driver, and in NetworkTask :^)
2019-07-14 14:54:54 +02:00
Andreas Kling
3073ea7d84 Kernel: Add support for the WSTOPPED flag to the waitpid() syscall.
This makes waitpid() return when a child process is stopped via a signal.
Use this in Shell to catch stopped children and return control to the
command line. :^)

Fixes #298.
2019-07-14 11:35:49 +02:00
Andreas Kling
6c87d3afa9 Kernel: Move i8253.cpp => Arch/i386/PIT.cpp 2019-07-09 15:04:45 +02:00
Andreas Kling
27f699ef0c AK: Rename the common integer typedefs to make it obvious what they are.
These types can be picked up by including <AK/Types.h>:

* u8, u16, u32, u64 (unsigned)
* i8, i16, i32, i64 (signed)
2019-07-03 21:20:13 +02:00
Andreas Kling
1277d583ef printf: Oops, '-' is the left padding modifier, not ' '.
It's kinda funny how I can make a mistake like this in Serenity and then
get so used to it by spending lots of time using this API that I start to
believe that this is how printf() always worked..
2019-06-22 15:53:52 +02:00
Andreas Kling
c1bbd40b9e Kernel: Rename "descriptor" to "description" where appropriate.
Now that FileDescription is called that, variables of that type should not
be called "descriptor". This is kinda wordy but we'll get used to it.
2019-06-13 22:03:04 +02:00
Andreas Kling
891d4c4834 Kernel: Qualify a bunch of #include statements. 2019-06-07 19:29:34 +02:00
Andreas Kling
bc951ca565 Kernel: Run clang-format on everything. 2019-06-07 11:43:58 +02:00
Andreas Kling
d194ce828d Kernel: Implement the alarm() syscall. 2019-06-07 11:30:07 +02:00
Andreas Kling
08cd75ac4b Kernel: Rename FileDescriptor to FileDescription.
After reading a bunch of POSIX specs, I've learned that a file descriptor
is the number that refers to a file description, not the description itself.
So this patch renames FileDescriptor to FileDescription, and Process now has
FileDescription* file_description(int fd).
2019-06-07 09:36:51 +02:00
Andreas Kling
b3a1671f1a Kernel: Add support for recv() with MSG_DONTWAIT.
Passing this flag to recv() temporarily puts the file descriptor into
non-blocking mode.

Also implement LocalSocket::recv() as a simple forwarding to read().
2019-05-20 03:47:02 +02:00
Andreas Kling
7900da9667 Kernel: Make sure we never put the colonel thread in the runnable list.
This would cause it to get scheduled unnecessarily.
2019-05-18 20:28:04 +02:00
Andreas Kling
8c7d5abdc4 Kernel: Refactor thread scheduling a bit, breaking it into multiple lists.
There are now two thread lists, one for runnable threads and one for non-
runnable threads. Thread::set_state() is responsible for moving threads
between the lists.

Each thread also has a back-pointer to the list it's currently in.
2019-05-18 20:28:04 +02:00
Andreas Kling
3cba2a8a78 Kernel: Add a beep() syscall that beeps the PC speaker.
Hook this up in Terminal so that the '\a' character generates a beep.
Finally emit an '\a' character in the shell line editing code when
backspacing at the start of the line.
2019-05-15 21:40:41 +02:00
Andreas Kling
03da7046bd Kernel: Prepare Socket for becoming a File.
Make the Socket functions take a FileDescriptor& rather than a socket role
throughout the code. Also change threads to block on a FileDescriptor,
rather than either an fd index or a Socket.
2019-05-03 20:15:54 +02:00
Andreas Kling
8cbb7f101f Kernel: Have File virtuals take a FileDescriptor& rather than a Process&.
This will allow us to implement different behaviors depending on the role
of the descriptor a File is being accessed through.
2019-04-29 13:58:40 +02:00
Andreas Kling
0a0d739e98 Kernel: Make FIFO inherit from File. 2019-04-29 04:55:54 +02:00
Andreas Kling
a9d09e9020 Kernel: Get rid of the "cool globals" thingy.
This was something I used while debugging with Computron. I haven't needed
it for months, so let's get rid of it. It's trivial to readd if needed.
2019-04-21 12:33:14 +02:00
Andreas Kling
ec365b82d5 Kernel: Make the colonel run at "Idle" priority (the lowest possible.)
This means it won't hog the CPU for more than a single timeslice. :^)
2019-04-20 15:58:45 +02:00
Andreas Kling
c59f8cd663 Kernel: Scheduler donations need to verify that the beneficiary is valid.
Add a Thread::is_thread(void*) helper that we can use to check that the
incoming donation beneficiary is a valid thread. The O(n) here is a bit sad
and we should eventually rethink the process/thread table data structures.
2019-04-17 12:41:51 +02:00
Andreas Kling
29d0412a06 Kernel: Remove system.h and make the uptime global a qword. 2019-04-14 01:29:14 +02:00
Andreas Kling
ab11f42094 Kernel: Do timekeeping manually instead of asking the RTC all the time.
This introduces a tiny amount of timer drift which I will have to fix
somehow eventually, but it's a huge improvement in timing consistency
as we no longer suddenly jump from e.g 10:45:49.123 to 10:45:50.000.
2019-03-25 02:06:57 +01:00
Andreas Kling
5713c3a0cb Kernel: Fix broken destruction order for Process/Thread. 2019-03-24 01:20:35 +01:00
Andreas Kling
6416123cfb Kernel: Set the colonel task to low priority.
This gives it a smaller time slice, improving responsiveness.
2019-03-23 22:22:01 +01:00
Andreas Kling
60d25f0f4a Kernel: Introduce threads, and refactor everything in support of it.
The scheduler now operates on threads, rather than on processes.
Each process has a main thread, and can have any number of additional
threads. The process exits when the main thread exits.

This patch doesn't actually spawn any additional threads, it merely
does all the plumbing needed to make it possible. :^)
2019-03-23 22:03:17 +01:00
Andreas Kling
bc1da7f1fd Kernel: Snooze the NetworkTask until there are incoming packets to process.
This is accomplished using a new Alarm class and a BlockedSnoozing state.
Basically, you call Process::snooze_until(some_alarm) and then the scheduler
won't wake up the process until some_alarm.is_ringing() returns true.
2019-03-20 17:09:46 +01:00
Andreas Kling
66d55f8e0c IPv4: More work on the TCP implementation.
I can now establish a connection to my little test server on the host.
2019-03-14 00:20:44 +01:00
Andreas Kling
562663df7c Add support for socket send/receive timeouts.
Only the receive timeout is hooked up yet. You can change the timeout by
calling setsockopt(..., SOL_SOCKET, SO_RCVTIMEO, ...).

Use this mechanism to make /bin/ping report timeouts.
2019-03-13 13:15:05 +01:00
Andreas Kling
a7d5e9781a Kernel+LibC+Userland: Yet more networking bringup hacking.
All ICMP sockets now receive all ICMP packets. All this buffering is gonna
need some limits and such.
2019-03-12 17:27:07 +01:00
Andreas Kling
1cc32ebc7e Kernel: Remove "requested wakeups" feature.
I only needed this to support the WindowServer living inside the kernel.
Now that it's been migrated to userspace, this can go. :^)
2019-03-05 13:34:36 +01:00
Andreas Kling
91031346e5 Kernel: More signal handling improvements.
Finally fixed the weird flaky crashing when resizing Terminal windows.
It was because we were dispatching a signal to "current" from the scheduler.
Yet another thing I dislike about even having a "current" process while
we're in the scheduler. Not sure yet how to fix this.

Let the signal handler's kernel stack be a kmalloc() allocation for now.
Once we can do allocation of consecutive physical pages in the supervisor
memory region, we can use that for all types of kernel stacks.
2019-03-05 12:52:35 +01:00
Andreas Kling
274b0260f7 Kernel: Don't send SIGCHLD to parent process if he has SA_NOCLDWAIT set.
Just transfer ownership of the dead process to the colonel and let the
scheduler reap it on next iteration.
2019-03-01 15:52:05 +01:00
Andreas Kling
e427b514dc Kernel: Implement basic SIGSTOP and SIGCONT support. 2019-02-28 12:27:26 +01:00
Andreas Kling
bf58241c11 Port the WindowServer and LibGUI to communicate through local sockets.
This is really cool! :^)

Apps currently refuse to start if the WindowServer isn't listening on the
socket in /wsportal. This makes sense, but I guess it would also be nice
to have some sort of "wait for server on startup" mode.

This has performance issues, and I'll work on those, but this stuff seems
to actually work and I'm very happy with that.
2019-02-14 17:18:35 +01:00
Andreas Kling
7ce15f1c54 Fix some compilation warnings. 2019-02-12 12:11:22 +01:00
Andreas Kling
fa241747af Kernel: When donating ticks to a lock holder, cap the donation.
When donating ticks to a lock holder, never donate more ticks than
that process would normally get from the scheduler.
2019-02-08 22:06:30 +01:00
Andreas Kling
71b9ec1ae0 Kernel: Add basic process priority support.
For now, the WindowServer process will run with high priority,
while the Finalizer process will run with low priority.
Everyone else gets to be "normal".

At the moment, priority simply determines the size of your time slices.
2019-02-07 12:21:17 +01:00
Andreas Kling
ee2bb98b88 Kernel: Increase default time slice to 20ms. 2019-02-07 11:53:45 +01:00
Andreas Kling
5582a0a254 Kernel: When a lock is busy, donate remaining process ticks to lock holder.
Since we know who's holding the lock, and we're gonna have to yield anyway,
we can just ask the scheduler to donate any remaining ticks to that process.
2019-02-07 11:14:58 +01:00
Andreas Kling
3fc3a8d7bc Kernel: Remove some unnecessary zero initialization now that BSS is cleared. 2019-02-07 10:31:32 +01:00
Andreas Kling
6cba80510e Kernel: Add a Finalizer process to take care of dying processes.
Instead of processes themselves getting scheduled to finish dying,
let's have a Finalizer process that wakes up whenever someone is dying.
This way we can do all kinds of lock-taking in process cleanup without
risking reentering the scheduler.
2019-02-06 18:45:21 +01:00
Andreas Kling
e05237485c Kernel: Various stability improvements.
- Don't cli() in Process::do_exec() unless current is execing.
  Eventually this should go away once the scheduler is less retarded
  in the face of interrupts.

- Improved memory access validation for ring0 processes.
  We now look at the kernel ELF header to determine if an access
  is appropriate. :^) It's very hackish but also kinda neat.

- Have Process::die() put the process into a new "Dying" state where
  it can still get scheduled but no signals will be dispatched.
  This way we can keep executing in die() but won't get our EIP
  hijacked by signal dispatch. The main problem here was that die()
  wanted to take various locks.
2019-02-06 17:34:27 +01:00
Andreas Kling
8cc6e304ca Kernel: Clean up around Scheduler::yield() a bit.
Also add assertion in Lock that the scheduler isn't currently active.
I've been seeing occasional fuckups that I suspect might be someone called
by the scheduler trying to take a busy lock.
2019-02-06 15:06:48 +01:00
Andreas Kling
b782055b96 Kernel: Add an InterruptFlagSaver helper class.
This is useful instead of InterruptDisabler in some cases.
2019-02-05 11:14:09 +01:00
Andreas Kling
0c38a4c30f WindowServer: Sever the WSWindow/Process link when the process dies.
This fixes a deadlock where the WindowServer would get stuck trying to
acquire a dead process's event stream lock.
2019-02-05 08:32:32 +01:00
Andreas Kling
d7307c3119 Kernel: Ignore SIGCHLD by default.
Also use an enum for the rather-confusing return value in dispatch_signal().
I will go through the rest of the signals and set them up with the
appropriate default dispositions at some other point.
2019-02-04 14:06:38 +01:00
Andreas Kling
c0cffe1134 Add a /bin/top program for process table monitoring.
It automagically computes %CPU usage based on the number of times a process
has been scheduled between samples. The colonel task is used as idle timer.
This is pretty cool. :^)
2019-02-04 10:28:12 +01:00
Andreas Kling
95c3442d59 Implement event loop timers.
GObjects can now register a timer with the GEventLoop. This will eventually
cause GTimerEvents to be dispatched to the GObject.

This needed a few supporting changes in the kernel:

- The PIT now ticks 1000 times/sec.
- select() now supports an arbitrary timeout.
- gettimeofday() now returns something in the tv_usec field.

With these changes, the clock window in guitest2 finally ticks on its own.
2019-02-01 03:50:06 +01:00
Andreas Kling
ffab6897aa Big, possibly complete sweep of naming changes. 2019-01-31 17:31:23 +01:00
Andreas Kling
dfdca9d2a7 Kernel: Implement lazy FPU state restore. 2019-01-25 07:52:44 +01:00
Andreas Kling
e911caeb10 Kernel: Fix dumb race in Scheduler::yield() debug code.
It was perfectly possible for Scheduler::yield() to get interrupted after
setting s_in_yield but before disabling interrupts.
2019-01-23 05:06:47 +01:00
Andreas Kling
4fef895eda Rework WindowServer to use select() in its main event loop.
The system can finally idle without burning CPU. :^)

There are some issues with scheduling making the mouse cursor sloppy
and unresponsive that need to be dealt with.
2019-01-16 17:20:58 +01:00
Andreas Kling
f7ca6d254d Tear out or duplicate what's unique for WindowServer from Widgets.
This turned into a huge refactoring that somehow also includes
making locks recursive/reentrant.
2019-01-16 16:03:50 +01:00
Andreas Kling
8ad2dfb6e1 Rename FileDescriptor::has_data_available_for_reading() -> can_read(). 2019-01-16 00:47:00 +01:00
Andreas Kling
10387beda7 Implement basic support for POSIX-style select().
Now we can block on both the PTY *and* the GUI event stream in Terminal.
2019-01-16 00:09:58 +01:00
Andreas Kling
e452303c66 Allow character devices to block write attempts until there is more space. 2019-01-15 09:17:22 +01:00
Andreas Kling
b0e3f73375 Start refactoring the windowing system to use an event loop.
Userspace programs can now open /dev/gui_events and read a stream of GUI_Event
structs one at a time.

I was stuck on a stupid problem where we'd reenter Scheduler::yield() due to
having one of the has_data_available_for_reading() implementations using locks.
2019-01-14 14:42:49 +01:00
Andreas Kling
7731aef7b2 Let the "reaped unparented process" messages go straight to the debugger. 2019-01-01 03:56:39 +01:00
Andreas Kling
033a42b580 The syncd loop can just be a lambda. 2018-12-24 23:10:48 +01:00
Andreas Kling
ec1c487dcd Yet another pass of style fixes. 2018-12-21 02:10:45 +01:00
Andreas Kling
e7cc08226f Implement basic support for times().
The kernel now bills processes for time spent in kernelspace and userspace
separately. The accounting is forwarded to the parent process in reap().

This makes the "time" builtin in bash work.
2018-12-03 01:14:19 +01:00
Andreas Kling
4bc87dc7b9 Share the "blocked-on file descriptor" number between read() and write().
A process can't be reading and writing at the same time, so it's fine for
them to share the variable for the blocked FD.
2018-12-03 00:42:48 +01:00
Andreas Kling
f6e27c2abe More coding style changes. 2018-12-03 00:39:25 +01:00
Andreas Kling
f5a83c4d8a Fix bug where a signal-interrupted waitpid() wouldn't return EINTR. 2018-11-28 23:30:49 +01:00
Andreas Kling
d90104f9e0 Let reap() communicate the dead process's exit status to the caller.
This way the scheduler doesn't need to plumb the exit status into the waiter.
We still plumb the waitee pid though, I don't love it but it can be fixed.
2018-11-28 22:01:24 +01:00
Andreas Kling
6cedb88153 Don't unblock a blocked process when it ignores a signal. 2018-11-16 21:14:25 +01:00
Andreas Kling
97c799576a Add close-on-exec flag for file descriptors.
I was surprised to find that dup()'ed fds don't share the close-on-exec flag.
That means it has to be stored separately from the FileDescriptor object.
2018-11-13 01:36:31 +01:00
Andreas Kling
f1404aa948 Add primitive FIFO and hook it up to sys$pipe().
It's now possible to do this in bash:

cat kernel.map | fgrep List

This is very cool! :^)
2018-11-12 01:28:46 +01:00
Andreas Kling
d5d45d1088 Rage hacking to get bash to run. It finally runs. So cool! :^) 2018-11-11 15:38:07 +01:00
Andreas Kling
e71cb1c56b Fix some paging related bugs exposed by the spawn stress test.
- Process::exec() needs to restore the original paging scope when called
  on a non-current process.
- Add missing InterruptDisabler guards around g_processes access.
- Only flush the TLB when modifying the active page tables.
2018-11-09 01:25:31 +01:00
Andreas Kling
e287f8ef3a The colonel task already had a halt loop.
Also don't reap() current in the scheduler, just wait until it's not current.
2018-11-08 00:30:35 +01:00
Andreas Kling
ac1d12465f Move timer tick handling into Scheduler. 2018-11-08 00:26:04 +01:00
Andreas Kling
1dbc340da8 Get rid of the undertaker and have waitpid() be the reaper.
For dead orphans, the scheduler calls reap().
2018-11-07 23:59:49 +01:00
Andreas Kling
f792349853 Unbreak sys$sigreturn() after colonel process changes. 2018-11-07 23:21:32 +01:00
Andreas Kling
43f40a3050 Finally unbreak the colonel process and make it the true idle process. 2018-11-07 23:14:56 +01:00
Andreas Kling
440029c9d1 Reduce number of passes in the scheduler by 2. 2018-11-07 22:24:20 +01:00
Andreas Kling
39d2fcbbee Move the scheduler code to its own class.
This is very mechanical.
2018-11-07 22:15:02 +01:00