This includes a new Thread::Blocker called SignalBlocker which blocks
until a signal of a matching type is pending. The current Blocker
implementation in the Kernel is very complicated, but cleaning it up is
a different yak for a different day.
Also, remove incomplete, superfluous check.
Incomplete, because only the byte at the provided address was checked;
this misses the last bytes of the "jerk page".
Superfluous, because it is already correctly checked by peek_user_data
(which calls copy_from_user).
The caller/tracer should not typically attempt to read non-userspace
addresses, we don't need to "hot-path" it either.
This is not actually implemented at the moment, as we do not support
sending or receiving out-of-band data at all currently, but it is
required for some ports to compile.
POSIX mandates that the macros contained in `stdint.h` be suitable for
use by the C preprocessor.
If we write `((size_t)-1)`, the C preprocessor will just skip the cast
and treat the value as `-1`. This means that we end up taking the wrong
branch in an `#if` directive like `#if SIZE_MAX > UINT32_MAX`.
This fixes building the LLVM port on i686.
x86_64 is an LP64 platform, so its `uint64_t` type is defined to be
`unsigned long`, not `unsigned long long` like on i686. This means that
the `UL` literal suffix should be used instead of `ULL`.
Furthermore, `uintptr_t` is 64 bits wide on x86_64, so defining
`UINTPTR_MAX` to be `UINT32_MAX` is also not correct.
This allows userspace to trigger a full (FIXME) flush of a shared file
mapping to disk. We iterate over all the mapped pages in the VMObject
and write them out to the underlying inode, one by one. This is rather
naive, and there's lots of room for improvement.
Note that shared file mappings are currently not possible since mmap()
returns ENOTSUP for PROT_WRITE+MAP_SHARED. That restriction will be
removed in a subsequent commit. :^)
C++17 introduced aligned versions of `new` and `delete`, which are
automatically called by the compiler when allocating over-aligned
objects. As with the regular allocator functions, these are generally
thin wrappers around LibC.
We did not have support for aligned allocations in LibC, so this was not
possible. While libstdc++ has a fallback implementation, libc++ does
not, so the aligned allocation function was disabled internally. This
made building the LLVM port with Clang impossible.
Note that while the Microsoft docs say that aligned_malloc and
_aligned_free are declared in `malloc.h`, libc++ doesn't #include that
file, but instead relies on the definition coming from `stdlib.h`.
Therefore, I chose to declare it in that file instead of creating a new
LibC header.
I chose not to implement the more Unix-y `memalign`, `posix_memalign`,
or the C11 `aligned_alloc`, because that would require us to
significantly alter the memory allocator's internals. See the comment in
malloc.cpp.
libc++ uses a Pthread condition variable in one of its initialization
functions. This means that Pthread forwarding has to be set up in LibC
before libc++ can be initialized. Also, because LibPthread is written in
C++, (at least some) parts of the C++ standard library have to be linked
against it.
This is a circular dependency, which means that the order in which these
two libraries' initialization functions are called is undefined. In some
cases, libc++ will come first, which will then trigger an assert due to
the missing Pthread forwarding.
This issue isn't necessarily unique to LibPthread, as all libraries that
libc++ depends on exhibit the same circular dependency issue.
The reason why this issue didn't affect the GNU toolchain is that
libstdc++ is always linked statically. If we were to change that, I
believe that we would run into the same issue.
`off_t` is a 64-bit signed integer, so passing it in a register on i686
is not the best idea.
This fix gets us one step closer to making the LLVM port work.
In particular, we track separately whether each AtExitEntry has already
been called, through a separate Bitmap. This has several side-effects:
- We now call malloc() during __cxa_finalize(). I believe this is fine,
and at that point during program execution memory pressure should be
low anyway.
- An attacker could prevent arbitrary entries from executing by writing
to atexit_called_entries. However, this already was possible (by
setting atexit_entry_count to zero), and this path is even more
troublesome (the attacker needs to overwrite atexit_called_entries,
and a region serving as *atexit_called_entries.m_data, and magically
know exactly how many entries already exist.)
- This reduces the size of AtExitEntry from 16 to 12 (on i686). As such,
we can reduce the initial memory allocation from two to one page,
reducing the initial capacity from 512 to 341 entries (or 256 to 170,
on x86_64). It seems that most programs only use 36-47 entries anyway.
For 'true', this shaves off about 69 syscalls, as measured by strace.
Same as Vector, ByteBuffer now also signals allocation failure by
returning an ENOMEM Error instead of a bool, allowing us to use the
TRY() and MUST() patterns.
Before this change, we would generate the static C library by running
the command `ar -qcs` to collect the various `*.o` files into a single
archive.
The `q` option stands for "quick append", which simply appends new files
to the archive, without replacing any pre-existing entries for the same
file. The problem with this is obvious: each LibC rebuild would add
approximately 1 MB (the size of a cleanly built libc.a) to the size of
the file. It got so bad on my machine that the total file size ended up
being 3 gigabytes.
Note that this did not affect the GNU toolchain, because, as the `ar(1)`
manpage says:
> Note - GNU ar treats the command qs as a synonym for r - replacing
> already existing files in the archive and appending new ones at the
> end.
We create a base class called GenericFramebufferDevice, which defines
all the virtual functions that must be implemented by a
FramebufferDevice. Then, we make the VirtIO FramebufferDevice and other
FramebufferDevice implementations inherit from it.
The most important consequence of rearranging the classes is that we now
have one IOCTL method, so all drivers should be committed to not
override the IOCTL method or make their own IOCTLs of FramebufferDevice.
All graphical IOCTLs are known to all FramebufferDevices, and it's up to
the specific implementation whether to support them or discard them (so
we require extensive usage of KResult and KResultOr, together with
virtual characteristic functions).
As a result, the interface is much cleaner and understandable to read.
Some ports (like `bc` with history enabled) sensibly set the termios
character size to 8 bits.
Previously, we left the character size value (given by the bitmask
CSIZE) as zero by default (meaning 5 bits per character), and returned
ENOTIMPL whenever someone modified it. This was dumb.
Also add a test to prevent this from happening again. There were two
bugs:
* The number of bytes just after processing the last value was written,
instead of the number of bytes after skipping remaining whitespace.
Confirmed by testing against GNU's `scanf()` since the man page
leaves something to be desired.
* The number of bytes was written to the wrong variable argument; i.e.
the first argument was overwritten.
We always use UTF-8, meaning that a single `wchar_t` might be converted
into up to 4 `char`s. This would cause a buffer overflow if something
actually relied on this being the right value.
The C standard states that these symbols should be declared as macros,
not as emum variants as we were doing previously. This is used in some
ports (e.g. bash) to conditionally compile locale-dependent
functionality.
We now use the same trick here as with the errno constants. We keep the
enum, but also create macros that defer to the enum variants.
The `wcsxfrm` function copies a wide character string into a buffer,
such that comparing the new string against any similarly pre-processed
string with `wcscmp` produces the same result as if the original strings
were compared with `wcscoll`.
Our current `wcscoll` implementation is simply an alias for `wcscmp`, so
`wcsxfrm` needs to perform no actions other than copying the string.