At that project scale, wouldn't it start making sense to start solving problems like "If it were possible to write a list-traversal macro that could declare its own iterator [...]" by adding the functionality you want to GCC?
At that project scale, wouldn't it start making sense to start solving problems like "If it were possible to write a list-traversal macro that could declare its own iterator [...]" by adding the functionality you want to GCC?
Deathtrap situation-- maintain an operating system and a fork of a compiler. Benefit: you can get more control over the compiler. Cost: you still cannot always get the compiler to behave as you think due to time constraints. Death cost: your first cost is multiplied by the fact that you're now maintaining a goddamned compiler.
I rankly speculate Linux is an extant project at its scale because it has refused to fight on two fronts like this. (And yelling across a border isn't the same as crossing it.)
Edit: clarifications
https://gcc.gnu.org/legacy-ml/gcc-patches/2009-07/msg01556.h...
Static keys are a kernel API that allows code modification at runtime to achieve zero cost feature flags, like tracing:
https://www.kernel.org/doc/html/latest/staging/static-keys.h...
It doesn't seem useful to make a "C+" instead of switching to a language that just has the feature set the kernel needs. Like Rust, which is gaining some support within the Linux kernel already.
If you started writing a major project in C now you'd rightfully get sacked, but open source projects like this are often dominated by the opinions of those who only work on that project. That doesn't mean they're automatically wrong but just that they're often massively detached from any feedback apart from disaster.
But that's exactly why I think a customized language for the kernel is an interesting idea. You could get pretty much exactly what you want for the kernel. Add features you need, remove any undesirable behavior or features.
For most programs that would be too much complexity, but the kernel has very particular needs. And I think a similar in spirit approach has worked very well with Qt.
C++ allowed the Serenity OS people to produce an entire OS with a GUI stack able to play Diablo and their own web browser in something like two years. It's depressing to think where we could be today in terms of OS if the Linux and GNU people weren't as insistent on their hate of C++
Simple question, simple answer. Using C is purely an act of risk-aversion, contrarianism, and fashion.
This is probably one of the biggest reasons I may turn to rust over C++ - simply less features creep due to less time being around.
Can you comment on how wrong I am about my feelings this way?
C++11 and newer are all largely one "category" in terms of recommendations. The CppCoreGuidelines is a good place to cover all that, but it's not a from-scratch introduction by any means
C++(17+) template based metaprogramming far more powerful and generic than what you can do in eg rust. Converting eg a rust or go or python, or julia, etc library into c++ is pretty straightforward, just use appropriate overloads, and a few template tricks, and you can mostly copy the code directly. But copying between these, or from c++ is much harder.
The solution is to learn one approach suitable for the problem you have right now, then widen over time. The many languages of c++ as you describe is less of a problem, the problem is that some approaches are deeply and fundamentally flawed, but still in common use.
I'm not necessarily advocating that Linux should switch to C++, just that there's probably not a good reason to invest in a new C/C++ hybrid language at this point in time. Not when C++11 is honestly pretty good, but also Rust, Zig, or even D's betterC all already exist.
In Rust, allocation lives in a library, alloc, and so the Rust for Linux project did all the work to offer alloc (it's full of useful stuff and it isn't like the Linux kernel can't allocate memory) but without implicit allocation.
If you use Rust to write say a Linux command line program, you can write
greeting += " and welcome traveller";
... and of course implicitly this is an allocation, 'cos it's not like this greeting variable just magically already has enough space to append a string. But in Rust for Linux, you can't do that, the implicitly allocating += operator is not provided on this type in their alloc library. If you want to say "Allocate more space for the greeting" you can do that of course, just as you can today in C but you must do so explicitly and so when you try to add 16GB of extra string space because you're an idiot, the API you had to explicitly call gives you an error and that's your problem.However the most critical reason Linux doesn't have C++ is that C++ proponents didn't do the work. Now, that will probably be because "reform the entire language to suit Linus" wasn't a viable plan, but the fact is that Linus can't accept patches that nobody writes, so even if you're sure C++ would be viable without drastic changes, you didn't write the patchset that does it. Likewise if people don't send Linus patches to do C11 it probably won't happen.
Ah, but see, it doesn't. Linus was wrong about many things in his rant. This being one of them.
Now the standard library does indeed have things that do implicit allocations, such as std::string. But these, like with Rust, are distinct from the language & replaceable. Would it be effort to make a kernel-safe std:: replacement? Yes. Would it be a lot of work? Not really. And it's the kind of thing Linux has been doing for decades with C anyway. It's not like they use a standard libc implementation (much less a rich libc implementation like glibc), for example.
And it's something game devs have been doing with C++ for decades without any issues, too.
So for this one you don't even have to ban anything. Just don't pass a standard library implementation to the compiler. It doesn't come with one, after all. You have to add it. So you could just... Not do that.
As for nobody did the work... That's true. But Linus also pretty much nuked the entire concept of using C++, regardless of the what or how. Time seems to have changed his mindset on some of those things, hence his reaction to Rust, which largely makes all this moot. But we shouldn't confuse short term politics with technical issues, either.
Its not what is being discussed here. C++ has an implementation defined memory model. That just cannot work with Linux out of the box. You need an OS and compiler designed from the ground up to handle this.
Only since C++11, and it's not a full blown memory model.
There is nothing when can do to change political views.
And lets not pretend that Rust in the kernel won't suffer from creative uses of macros, and there is still a big laundry list of issue to fix before it actually makes it.
Or that for the time being, Rust compilers need to link to C++ code to actually work, at least until Cranelift is a match in code quality against LLVM or GCC.
So in the end Linus gets C++ into the kernel, even if indirectly.
GCC itself has been written in C++ since 2010.
If they switched to c++17, and banned everything from throw and RTTI to the standard library, they would still get for each, auto, and templates and inheritance which does not have to be emulated in C.
I tend to agree, as a C++ developer. There are many core issues in the language that haven't been resolved and that are unacceptable for kernel code.
My personal pet peeve: C++ is unable to reallocate a new[] region. This makes basically all structures (vector, hashmap, trees...) unusable for large data handling.
But this is assuming you have a malloc implementation that does something other than implement realloc as just malloc+memcpy+free. Which not many do, not unless the allocation is so large as to be in its own dedicated mmap or similar.
That aside, sure would be great if you elaborated on these unsuitable, unresolved for kernel language issues? Exceptions and rtti are the only two I'm aware of and both have had off switches for decades.
Sure, but basically it means rewriting all structures that rely on a bucket of stuff.
By the way maps often use a large bucket, and rehash in-place can be preferable.
> Which not many do, not unless the allocation is so large as to be in its own dedicated mmap
Do you know a modern operating system that does not have a mremap equivalent ?
On Linux you pretty much use it as soon as you reach large blocks.
std::unordered_map (what I'm guessing you meant by a hashmap) uses a linked list for the nodes. There's no movement in the first place to worry about being realloc'd.
> Do you know a modern operating system that does not have a mremap equivalent ?
You have to be very large before most mallocs will put you on a dedicated mmap that can even be mremap'd at all.
If you're working with stonking huge data inline in a std:: vector... Yeah just make a container for that usage, not really an issue. There's tons of examples out there, typically to add SSO but doing realloc would be the same basic thing.
It really, truly is not comparable. list_for_each_entry does a well known operation that's just moving some pointers around. Safe to do while holding a spinlock, or in interrupt context, etc.
std::for_each is a generic iterator implementation. What code runs in order to iterate? Will it transparently take locks, risking a deadlock? Will it need to schedule()? You don't need to ask those questions about the standard linked list macro, and that has a lot of value when every instruction the compiler generates might matter.
All your other stuff about for_each is just... Wrong? It's all well defined what it does. The substitutions that for_each makes and exactly what it calls are all defined.
You could give it a container that does something stupid, but you could also give list_for_each_entry the wrong field or accidentally use it when it's no longer valid (literally the bug being fixed)
I suppose the thrust of my opinion is that a lot of code depends on the fact that it iterates over a linked list, which is safe in many contexts. The idea that callers could substitute container types which break its assumptions seems unwelcome to me. Nobody provides the wrong fields to list_for_each_entry because they get very nasty compiler errors if they try. But anybody can plug a new container type into a for each statement and get new behavior that silently breaks the assumptions of the original code.
I suppose that could be protected by a better type system though. There's a lot to improve on C even for kernel dev, and "C is greatest" isn't a hill I'm willing to die on :)
How would it be "silent"? You're changing the container at the point where you're making any assumptions about it. This would just fall under normal code review purview, just like code reviews are how Linux enforces that anyone even used this linked list macro in the first place. C certainly doesn't care if you use list_for_each_entry for your container iteration, after all.
But it'd be a lot easier to replace these linked lists with a vector that has the same observable contract if C++ was used, just would be way faster to iterate on.
{ iter= xs.begin(); while(iter++ != xs.end()){L} } Not exactly hard to see what happens. In particular as iter is typically just a raw pointer.
Regardless of if you use one or the other you must answer the question, Should I take locks, etc.
With the macro you also have the concern that if any of the headers you include happens to change order of inclusions, the macro called may change without being noticeable. That is a harder problem.
If some shenanigans were to happen upstream in GCC it would not be the end of Linux.
> The Linux kernel has always traditionally been compiled with GNU toolchains such as GCC and binutils. Ongoing work has allowed for Clang and LLVM utilities to be used as viable substitutes. Distributions such as Android, ChromeOS, and OpenMandriva use Clang built kernels. LLVM is a collection of toolchain components implemented in terms of C++ objects. Clang is a front-end to LLVM that supports C and the GNU C extensions required by the kernel, and is pronounced “klang,” not “see-lang.”