Re: The Case for Rust (in any system)

From: Warner Losh <imp_at_bsdimp.com>
Date: Sun, 08 Sep 2024 17:30:20 UTC
On Sun, Sep 8, 2024, 9:05 AM David Chisnall <theraven@freebsd.org> wrote:

> On 8 Sep 2024, at 14:50, Warner Losh <imp@bsdimp.com> wrote:
>
>
> So there's four big issues with C++ in the kernel, all surmountable if we
> wanted.
>
>
> There are two missing from your list, which I encountered when I wrote a
> kernel module for FreeBSD in C++ a few years ago:
>
> C++ relies on COMDATs quite a lot.  Each inline function and each function
> that’s instantiated as a template is a separate section with some flags
> indicating that the linker / loader should keep one and discard the rest.
> If you have a single C++ module, this is fine, but for two it’s harder.  I
> did a small ‘libkxx’ module that provided a subset of libc++ for use by
> different modules, but the kernel loader code didn’t have enough comments
> for me to understand how to fix it. I would be tempted to approach this
> with a userspace tool that runs over a set of kernel modules and pulls out
> duplicated COMDATs into separate modules that other things can depend on.
> Alternatively, the kernel loader could be modified to load only referenced
> COMDATs, reference count them, and not load unused things from each kernel
> module.  The latter is a cleaner approach but is more work.
>
> Second, between 11 and 12, someone decided to replaces a load of static
> inline functions in kernel headers with macros.  These conflict a lot.
>
> There's the low-level allocation issues. Right now we know what memory is
> used by what because we have malloc enhanced to track this (oversimplifying
> a lot I know). So we'd need some framework to make it easy to have 'custom
> allocators' that could track it as well. At a bare minimum, we need the
> runtime support for new and delete...
>
>
> This is not technically required, but it is a good idea to think about
> what the right strategy is.  A C++ class can implement its own `operator
> new` and `operator delete` wrapping `malloc(9)` and then subclasses will
> allocate with that.  Similarly, things like `std::unique_ptr` can take an
> explicit deleter.
>
> This can be a bit clunky and it’s probably a good idea to have some
> sensible defaults.
>
> Next, there's all the other run-time support that's provided by
> compiler-rt.
>
>
> Nothing in compiler-rt is needed for C++ except the unwinder if you want
> exceptions (no one else except NT uses exceptions in a kernel).  The one
> bit of libcxxrt that you would probably want is the support for guard
> variables, which would need modifying to use kernel locks.  This is fairly
> small, I wrote a custom one for CHERIoT RTOS which uses our futex APIs.
>
> Next, there's the issues of exceptions. They are quite useful for RAII
> (since you know dtors will get run when an error happens), and there'd need
> to be some sane plan for these (or we'd have to forego them).
>
>
> Most kernels disable exceptions.  You absolutely do not want Itanium-style
> exceptions in a kernel because they need to allocate to throw exceptions
> and so you would only be able to throw from places where allocation is
> safe.  Given that the most common place you’d want to throw an exception
> (if you had them) is if `malloc` with `M_NOWAIT` failed, this could be a
> problem.
>
> NT uses SEH exceptions, which allocate all of the state on the stack and
> then run funclets for cleanup.  It would be possible to support this in the
> kernel (the relevant patents expired over ten years ago), but a non-trivial
> amount of work.  If someone wanted to do the work, it would be great: SEH
> is one of the very few things I really liked about the NT kernel.
>
> Finally, there's getting the subset of the standard library that's useful
> into the kernel. There's a lot of templates for facilitating RAII that are
> needed, for example, and some subset of STL, etc.
>
>
> You don’t need templates for RAII, RAII just depends on destructors.
> Templates are useful, but largely orthogonal.  I’d personally recommend
> against using much of the standard library in the kernel because it does
> not have good ways of handling allocation failure without exceptions.  The
> C++ standard defines a Freestanding profile (similar to C) that includes
> things like the type traits that are useful for compile-time
> metaprogramming.  There are a few bits you might want to pull in but a lot
> more that you’d want to avoid (I actually have iostream working with the
> kernel’s printf family, but it was a terrible idea and no one should ever
> use that code).
>
> For example, `std::shared_ptr` is probably not a good idea (it allocates a
> separate control block to hold the ref count), but something that wraps
> things that are intrusively reference counted with `refcount(9)` in smart
> pointers would be valuable.  Using member pointers, it’s easy to build a
> smart-pointer template that takes a C type that contains a refcount and a
> pointer to the field and automatically manipulates the reference count when
> you copy the pointer.
>
> Once you have those 'table stakes' issues out of the way, you'll need to
> see how it performs, and work out a few dozen logistical issues surrounding
> what compiler flags to use, what language features to enable/disable, how
> to optimize and what set of warnings are sensible.
>
>
> -fno-exceptions and -fno-rtti is what most peopls use for kernel
> programming (there are a few dozen kernels written in C++, it’s not like
> we’d be the first to try).
>
> You could start using C++ with just the second of these items.
>
>
> You can use it within a single kernel module now, as long as you resolve
> COMDATs prior to linking and #undef a bunch of things.  I was doing so five
> years ago.  The build system actually supports it already, though possibly
> not deliberately.
>

I did C++ in the kernel in the 4.x->7-current time frame. I stopped because
g++ was still evolving a lot in that time period and things kept
breaking... and our use of C++ wasn't so big that rewriting in C was hard
when one of the compiler updates in base broke something. A lot has changed
since then and I'm just extrapolating from that... your experience is much
more recent.

Warner

David
>
>