3 ms·
Given that this is the kernel, using typical C++ libraries would be out of the question, so it should be easy enough to design things right from the start. C++
by blub 5y ago
Given that this is the kernel, using typical C++ libraries would be out of the question, so it should be easy enough to design things right from the start.
C++ is after all used in embedded contexts where allocations are forbidden and it offers excellent support for this use case.
In such a project where allocations matter one would not stare at class definitions, one would ensure that there are no allocations by forbidding use of libraries like the STL and for example disabling operator new and the copy constructor. If the project is safety-critical there are tools which can enforce such rules.
Edit: I've clarified that I was referring to C++ libraries only.
- kibwen 5y agoUsing Rust's stdlib isn't out of the question for the kernel, at least not the most fundamental bits of the stdlib. Rust offers a well-defined subset of its stdlib, called libcore, that is suitable for embedded work: no allocations, no OS-provided abstractions, etc. So you don't get HashMap or Vec, but you do get Option, Iterator, str (but not String, the heap equivalent), etc.
- tialaramex 5y agoAh, I think there is a misconception at work here. The problem isn't "Kernel code should not allocate" but "Kernel code should not implicitly allocate". And C++ thinks this is none of your business. You can have no allocation by not providing an allocator - but you can't have no implicit allocation because the language will go out of its way to hide some of the obvious places allocation might happen rather than expose its warts.
- blub 5y agoCould you give me an example of such implicit allocations that are done by the language and would be a problem in a kernel context? Here's my list: * RTTI: would be disabled * Exceptions: would be disabled * STL, stdlib: would not be used
- geofft 5y agoYou'd need some sort of standard library, even if not the normal userspace one. The kernel has a pretty sizable "lib" directory which includes all the string functions etc. you'd expect in normal userspace C. For the Rust-for-Linux work we're using the Rust standard library's libcore and liballoc, just a slightly forked version of liballoc with the goal of getting any changes upstream once we get some experience about what works well. (Along those lines, the kernel has a non-allocating printk() that works like userspace printf(), and we provide non-allocating Rust wrappers that mimic userspace println!(). C++ in the kernel would want a non-allocating iostream, I think.) I think you could address this point by using a slightly forked version of a C++ standard library that marked all its allocating constructors and allocating conversion functions with the "explicit" keyword. (But you wouldn't be able to upstream this, ever.) I'm not sure if there's any other case where you'd have implicit allocations that you wouldn't be able to avoid. You may be right that this is doable entirely with library changes provided you avoid RTTI and exceptions. One specific weird case is the copy done when capturing things into a lambda: https://godbolt.org/z/Y7fG5hjqq https://godbolt.org/z/Y7fG5hjqq I expect the first allocation here because I'm explicitly calling the constructor, and that's fine, but the second one surprises me a bit, because the copy constructor is marked "explicit". Maybe people who work with C++ more regularly than me find this less surprising. But that goes back to the problem 'tialaramex raised, about how "How many allocations does this do?" is a quiz question. Distinguishing zero from at-least-one is important, and you can do that by avoiding any heap-allocated-container types entirely, but so is distinguishing one from more-than-one.
- tialaramex 5y agoFor example the C++ language implicitly runs constructors, which may (or may not, it depends) cause allocation, whenever it sees fit to construct any object, even if that object is temporary and will be destroyed immediately afterwards. Now of course you could say, "Oh I never use objects, those are awful" but then you ought to ask yourself what exactly the point was of having C++ at all. Or you could say, "We'll ban constructors from allocating" but C++ won't help you enforce that rule and the resulting code won't be idiomatic C++. Implied allocation is just normal in C++. Also note that although Rust's full standard library won't be available in the kernel, you do get Vectors, you get Rust's reference counted "smart pointer" types, Iterators, Option and Result and so on. In Rust such things don't have implied allocation, only explicit allocation which is fine. Rust used today in the real world does have some places with implied allocation, a notable example is String concatenation. Rust won't let you write let hw = "Hello, " + "world"; However, the String implementation in the Rust standard library, and currently in kernel Rust, will let you write: let h = "Hello".to_owned(); // Now it's a String let hw = h + ", world"; But, that's one of the anticipated objections from Linus, and you'd just remove AddAssign (and possibly Add) from the Strings to cure it by forcing programmers to actually spell out what they want to happen here instead of acting as though concatenating strings is free.