Calling systrace(pid) gives you a file descriptor with a stream of the
syscalls made by a peer process. The process must be owned by the same
UID who calls systrace(). :^)
I was originally implementing signals by looking at some man page about
sigaction() to see how it works. It seems like the restorer thingy is
system-specific and not required by POSIX, so let's get rid of it.
Cooperate with the compiler to generate and execute the _init_array list
of constructor functions on userspace program statup. This took two days
to get working, my goodness. :^)
Since this program is primarily used to display potentially huge but still
static images, let's not put extra strain on the system by double buffering.
We now talk to the lookup server over a local socket and it does the lookup
on our behalf. Including some retry logic, which is nice, because it seems
like DNS requests disappear in the ether pretty damn often where I am.
This patch adds a simple GMessageBox that can run in a nested event loop.
Here's how you use it:
GMessageBox box("Message text here", "Message window title");
int result = box.exec();
The next step is to make the WindowServer respect the modality flag of
these windows and prevent interaction with other windows in the same
process until the modal window has been closed.
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.
It's now actually possible to ping other hosts on the network! :^)
I've switched the "run" script over to starting QEMU with user networking
since that works better for my testing needs right now.
When passing O_CREAT to open(), it will grab a third "mode" argument from
the stack. Let's not forget to actually pass this!
Also use the process umask for the created files.
Katica is now the default system font, and it looks quite nice. :^)
I'm gonna need to refine the GTextBox movement stuff eventually,
but it works well-enough for basic editing now.
It's now possible to create symbolic links! :^)
This exposed an issue in Ext2FS where we'd write uninitialized data past
the end of an inode's content. Fix this by zeroing out the tail end of
the last block in a file.
Let GButton have an optional icon (GraphicsBitmap) that gets rendered in the
middle of the button if present.
Also add GraphicsBitmap::load_from_file() which allows mmap'ed RGBA32 files.
I wrote a little program to take "raw" files from GIMP and swizzle them into
the correct byte order.
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.
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.
While working on the ELF loader I was trying to keep binaries as simple as
possible so I could understand them easily. Now that the ELF loader is mature
and working fine, we can move closer towards ld defaults.
Clicking the button generates a WindowCloseRequest event which the client app
then has to deal with. The default behavior for GWindow is to close() itself.
I also added a flag, GWindow::should_exit_event_loop_on_close() which does
what it sounds like it does.
This patch exposed some bugs in GWindow and GWidget teardown.
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.
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. :^)
FileDescriptor will now keep a pointer to the original inode even after
opening it resolves to a character device.
Fixed up /bin/ls to display major and minor device numbers instead of size
for device files.
You can now open as many PTY pairs as you like. Well, it's actually capped
at 8 for now, but it's just a constant and trivial to change.
Unregistering a PTY pair is untested because I didn't want to start
mucking with that in Terminal right now.
Only raw octal modes are supported right now.
This patch also changes mode_t from 32-bit to 16-bit to match the on-disk
type used by Ext2FS.
I also ran into EPERM being errno=0 which was confusing, so I inserted an
ESUCCESS in its place.
It's really only supported in Ext2FS since SynthFS doesn't really want you
mucking around with its files. This is pretty neat though :^)
I ran into some trouble with HashMap while working on this but opted to work
around it and leave that for a separate investigation.
- Make it track the mouse cursor just like GButton does so that changes only
get committed if the mouseup event happens while inside the widget rect.
- Draw a focus rect around the box when appropriate.
- When focused, support toggling the checked state with the space bar.
Instead of clients painting whenever they feel like it, we now ask that they
paint in response to a paint message.
After finishing painting, clients notify the WindowServer about the rect(s)
they painted into and then flush eventually happens, etc.
This stuff leaves us with a lot of badly named things. Need to fix that.
To start painting, call:
gui$get_window_backing_store()
Then finish up with:
gui$release_window_backing_store()
Process will retain the underlying GraphicsBitmap behind the scenes.
This fixes racing between the WindowServer and GUI clients.
This patch also adds a WSWindowLocker that is exactly what it sounds like.
This patch adds most of the plumbing for working file deletion in Ext2FS.
Directory entries are removed and inode link counts updated.
We don't yet update the inode or block bitmaps, I will do that separately.
This is pretty cool. :^)
GraphicsBitmaps are now mapped into both the server and the client address
space (usually at different addresses but that doesn't matter.)
Added a GUI syscall for getting a window's backing store, and another one
for invalidating a window so that the server redraws it.
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.
It walks all the live Inode objects and flushes pending metadata changes
wherever needed.
This could be optimized by keeping a separate list of dirty Inodes,
but let's not get ahead of ourselves.
This synchronous approach to inodes is silly, obviously. I need to rework
it so that the in-memory CoreInode object is the canonical inode, and then
we just need a sync() that flushes pending changes to disk.
(Don't) use this to implement short-form output in ls.
I'm too tired to make a nice column formatting algorithm.
I just wanted something concise when I type "ls".
Pass the file name in a stack-allocated buffer instead of using an AK::String
when iterating directories. This dramatically reduces the amount of cycles
spent traversing the filesystem.
After I made stdio buffered, we were dropping anything unflushed on exit.
Since /bin/clear just prints out some escape sequences without a newline,
the entire buffer was being discarded.
Also add VirtualConsole::clear() that handles clearing of background VC's.
All right, we can now mmap() a file and it gets magically paged in from fs
in response to an NP page fault. This is really cool :^)
I need to refactor this to support sharing of read-only file-backed pages,
but it's cool to just have something working.
This is dirty but pretty cool! If we have a pending, unmasked signal for
a process that's blocked inside the kernel, we set up alternate stacks
for that process and unblock it to execute the signal handler.
A slightly different return trampoline is used here: since we need to
get back into the kernel, a dedicated syscall is used (sys$sigreturn.)
This restores the TSS contents of the process to the state it was in
while we were originally blocking in the kernel.
NOTE: There's currently only one "kernel resume TSS" so signal nesting
definitely won't work.
Processes are either alive (with many substates), dead or forgiven.
A dead process is forgiven when the parent waitpid()s on it.
Dead orphans are also forgiven.
There's a lot of work to be done around this.
It only works for sending a signal to a process that's in userspace code.
We implement reception by synthesizing a PUSHA+PUSHF in the receiving process
(operating on values in the TSS.)
The TSS CS:EIP is then rerouted to the signal handler and a tiny return
trampoline is constructed in a dedicated region in the receiving process.
Also hacked up /bin/kill to be able to send arbitrary signals (kill -N PID)
This is quite cool! The syscall entry point plumbs the register dump
down to sys$fork(), which uses it to set up the child process's TSS
in order to resume execution right after the int 0x80 fork() call. :^)
This works pretty well, although there is some problem with the kernel
alias mappings used to clone the parent process's regions. If I disable
the MM::release_page_directory() code, there's no problem. Probably there's
a premature freeing of a physical page somehow.
We now make three VirtualConsoles at boot: tty0, tty1, and tty2.
We launch an instance of /bin/sh in each one.
You switch between them with Alt+1/2/3
How very very cool :^)
The SpinLock was all backwards and didn't actually work. Fixing it exposed
how wrong most of the locking here is.
I need to come up with a better granularity here.
- sys$readlink + readlink()
- Add a /proc/PID/exe symlink to the process's executable.
- Print symlink contents in ls output.
- Some work on plumbing options into VFS::open().
This shows some info about the MM. Right now it's just the zone count
and the number of free physical pages. Lots more can be added.
Also added "exit" to sh so we can nest shells and exit from them.
I also noticed that we were leaking all the physical pages, so fixed that.
This took me a couple hours. :^)
The ELF loading code now allocates a single region for the entire
file and creates virtual memory mappings for the sections as needed.
Very nice!
I also added a generator cache to FileHandle. This way, multiple
reads to a generated file (i.e in a synthfs) can transparently
handle multiple calls to read() without the contents changing
between calls.
The cache is discarded at EOF (or when the FileHandle is destroyed.)
It's implemented as a separate process. How cute is that.
Tasks now have a current working directory. Spawned tasks inherit their
parent task's working directory.
Currently everyone just uses "/" as there's no way to chdir().
I added a dead-simple malloc that only allows allocations < 4096 bytes.
It just forwards the request to mmap() every time.
I also added simplified versions of opendir() and readdir().
- Turn Keyboard into a CharacterDevice (85,1) at /dev/keyboard.
- Implement MM::unmapRegionsForTask() and MM::unmapRegion()
- Save SS correctly on interrupt.
- Add a simple Spawn syscall for launching another process.
- Move a bunch of IO syscall debug output behind DEBUG_IO.
- Have ASSERT do a "cli" immediately when failing.
This makes the output look proper every time.
- Implement a bunch of syscalls in LibC.
- Add a simple shell ("sh"). All it can do now is read a line
of text from /dev/keyboard and then try launching the specified
executable by calling spawn().
There are definitely bugs in here, but we're moving on forward.