4 ms·
You're talking about migrating kernel code to C++, but I'm talking about supporting C++ code in the kernel. That is, if third parties wanted to write Linux driv
by fluoridation 4y ago
You're talking about migrating kernel code to C++, but I'm talking about supporting C++ code in the kernel. That is, if third parties wanted to write Linux drivers, the only supported way was to do it in C.
That aside, the kernel does do polymorphism the hard way (with unions and arrays of function pointers) in a few places; the example I saw was some filesystem code, I think. C++ is also much more type-safe than C, mostly by refusing to implicitly convert between unrelated pointer/reference types and preventing you from inadvertently doing something absurd. References also make null checks unnecessary and convey to the caller that they're supposed to pass something valid, and RAII simplifies a lot of resource management. Templates also reduce boilerplate and are type-safe, although they're also a harder sell and not everyone's cup of tea.
I agree that memory safety is a huge advantage (although on the other hand, a double linked list in Rust is currently impossible without unsafe blocks), but I refuse to believe this decision has nothing to do with stubbornness.
- tsimionescu 4y ago> the kernel does do polymorphism the hard way (with unions and arrays of function pointers) in a few places Using C++ classes has some disadvantages compared to C-style polymorphism - especially related to memory layout and allocation - in C++, memory is allocated by the code instantiating the object, not by the object's code, so you have to know the size of the type (including private fields) in any place where you are instantiating it. Not sure how relevant this is for kernel code. > C++ is also much more type-safe than C, mostly by refusing to implicitly convert between unrelated pointer/reference types and preventing you from inadvertently doing something absurd This part I agree with. > References also make null checks unnecessary and convey to the caller that they're supposed to pass something valid I think the distinction between references and pointers is one of C++'s worse ideas. You can't generally replace pointers with references either. > RAII simplifies a lot of resource management RAII doesn't work without bringing in a whole lot of other heavy-duty features: mainly exceptions, but also constructors and destructors. > Templates also reduce boilerplate and are type-safe Templates are more type-safe than macros, but not that much more (since the template language is essentially a dynamically-typed program, even though its output is a C++ AST that will be further type-checked). Like RAII, they also require you to use other features of C++, especially operator overloading, and likely also copy (and more recently, move) constructors. > I agree that memory safety is a huge advantage (although on the other hand, a double linked list in Rust is currently impossible without unsafe blocks), but I refuse to believe this decision has nothing to do with stubbornness. I do agree that stubbornness may well be a component. However, I believe that there is a coherent argument that can be made that supporting C++ for kernel modules is not worth it, while supporting Rust for kernel modules is. I'm not saying that this is the argument that Linus is making, but I do believe it can be made. Especially since we also need to remember that all kernel modules are part of the kernel source tree. Supporting an additional language has a significant cost for everyone who is maintaining the kernel, since they need to add tooling to handle that extra language for all targeted platforms. It should also be remembered that C++ compilers are even worse than C compilers at mis-using instances of undefined behavior to mis-optimize code, especially since they typically rely even more on optimization steps to have half-decent performance.
- jcranmer 4y ago> RAII doesn't work without bringing in a whole lot of other heavy-duty features: mainly exceptions, but also constructors and destructors. You don't need exceptions to make RAII work. It does make fallible resource allocation a little bit trickier (the RAII object needs to be prepared to be in a live-but-failed-allocation state), but it's very doable. Constructors and destructors are absolutely not heavy-duty features.
- tsimionescu 4y agoThey are heavy duty precisely because they rely on exceptions to signal error conditions (or, in the case of destructors, are completely unable to signal errors safely at all), at least in combination with RAII. Without exceptions, RAII is quite cumbersome - especially in kernel mode, where you can't assume that memory allocation is always successful, so even memory allocation is a fallible resource allocation. Not to mention, RAII makes it impossible to check whether you successfully released the resource, which is a concern that the kernel can't always ignore the way user-space C++ code usually can.
- fluoridation 4y agoThe key to RAII is not so much constructors as destructors. If you want to be able to signal construction failure you just have an init() member function that returns a bool or some integer. As for dynamic allocation, when I worked on driver development for Windows, I just had an allocate<T>() function that returned a properly constructed std::unique_ptr<T> with the deallocation function properly set and with the T fully constructed (you may need more than one allocation function if you need to allocate from multiple contexts that require allocation in slightly different ways). >Not to mention, RAII makes it impossible to check whether you successfully released the resource Actually, RAII makes it much easier by encoding that knowledge into the owning object. Using the example above, you could call allocate<T, do_something_special_on_deallocation_failure>(). Then whenever the pointer goes out of scope you'll do the special thing without the user of the object having to know what that special thing is.
- account42 4y ago> You're talking about migrating kernel code to C++, but I'm talking about supporting C++ code in the kernel. That is, if third parties wanted to write Linux drivers, the only supported way was to do it in C. That hasn't really stopped anyone who wants to write their out of tree drivers in C++. > That aside, the kernel does do polymorphism the hard way (with unions and arrays of function pointers) C++ virtual functions are needlessly inefficient for interface classes where you only have a handful instances for each implementation (most commonly only one). Support for something like structs of function pointers with a little bit of sugar so you don't need to explicitly pass the this pointer would be very velcome even outside kernel space.