C++ In The Linux kernel 850
An anonymous reader submits "A researcher at Reykjavik University Network Laboratory (netlab.ru.is) has just released a Linux patch allowing for complete kernel-level run-time support for C++ in the Linux kernel, including exceptions, dynamic type checking and global objects (with constructors and destructors) The implementation is based on the C++ ABI in GNU g++, but contains various kernel level optimizations, that reduces the cost of throwing exceptions by an order of magnitude, thus making C++ exceptions viable in several scenarios. Furthermore, the Linux module loader is extended to handle weak symbols in C++, so that dynamic type checking is reduced to a pointer comparison, in contrast to string comparison."
nice (Score:5, Funny)
Who cares? (Score:3, Funny)
Re:nice (Score:4, Insightful)
The core of Windows in C++? Maybe I am wrong, but If my memory serves me well, it was C and asm.
Re:nice (Score:5, Informative)
I don't suspect you will be finding C++ in NTOSKRNL any time soon. I think Cutler would beat up anybody who tried.
Re:nice (Score:4, Interesting)
Actually most APIs that need to be used by alot of people have a C interface, no matter in what language they where written in. Has nothing to do with them being "MICROS~1"...
Re:nice (Score:4, Interesting)
Also, a C++ API is difficult to use if you are programming in C (or Pascal or FORTRAN, etc) where some languages don't have objects. Sure it can be faked, but thats exactly what the GDI API was, a front end for the C++ code underneath.
So even though the underlaying implementations of pens, regions, patterns and such is in C++ you still deal with them via handles. In fact, technical issues aside a C++ GDI API at the time made no sense for another reason: Windows (16-bit) compatability.
There was a big push by Microsoft to make the Win16 to Win32 converstion as much of a recompile as possible. Why else would we still have global and local memory? Such horrid things should have been dispatched to the land of the arcane years ago.
More Confusion (Score:5, Funny)
Comment removed (Score:5, Funny)
Re:More Confusion (Score:5, Funny)
With the GNU Compiler Collection able to generate machine code for Java, we'd be able to leverage all the things that Java excells at!
Such as:
umm....
well,
Oh forget it then.
kinda useless... (Score:4, Interesting)
Really, more useful would be a full-fledged java-based x86 or whatever simulator with emulated hardware that a kernel would target. Then any standard propietary binaries could run in that, and even be migrated across an java cluster.
Re:More Confusion (Score:5, Funny)
a) CKernelCrash
b) CKernelPatchNotGetAcceptedByLinus
One or the other, I'm sure.
Re:More Confusion (Score:4, Funny)
throw new ExceptionPatchNotAccepted("Linus");
Re:More Confusion (Score:3, Insightful)
Note: if you use ALL the techniques of C++ in your programs at the same time, then you are not a good programmer, period.
Re:More Confusion (Score:5, Insightful)
No, C solves problems differently.
Re:More Confusion (Score:5, Insightful)
"Exception Handling"
setjmp(), longjmp()
"Function Overloading"
Function pointers
"Operator overloading"
Ok , you can't do this in C.
"New/Delete"
Its easy to create simple malloc()/free() wrapper functions.
"Inline Comments"
Eh? Whats stopping you doing
"References"
These are hardly a selling point of C++ in my opinion. Implicit pass by address symantics should NEVER have been put in a modern language. Besides , after compilation they produce the same code as that using pointers.
"Others I'm sure"
Inheritance, templates etc. It just depends on how much you way syntatic clarity (C) against functional clarity (C++). Personally I think anyone who sticks religiously to either C or C++ without every using the other probably isn't a very competant programmer.
Re:More Confusion (Score:4, Informative)
Sorry to break it to you pal, but you don't have to have classes to use these constructs, they work perfectly well with primitives and structs. Obviously they become much more useful in an OOP world, but they aren't part of OOP.
pass-by-reference is not a programming methodlogy either... it's just a function of C++.
No one said anything about programing methodologies. Your original post said:
In fact I can't think of any other reasons to use C++ over C aside from classes and the various forms of inheritance.
I just stated some language features available in C++ that aren't in C that are potential reason to use C++ over C (that aren't related to classes and inheritance).
Re:More Confusion (Score:4, Insightful)
"References"
These are hardly a selling point of C++ in my opinion. Implicit pass by address symantics should NEVER have been put in a modern language.
Are you joking? References are the ultimate syntactic way to say "don't mess with the pointer, just use the object". The fact that you can't do arithmetic on references, or delete references, or assign references, without casting them in various ways is exactly the kind of friendly reminder that helps prevent a large class of common pointer-related programmer errors.
Besides, after compilation they produce the same code as that using pointers.
So does asm.
Anyhow, C has got issues. C++ added constructs to automate many aspects of modern programming, the point being to help reduce bugs by giving friendly syntactical shortcuts and reminders, and writing some of the code for you. It's not an issue of what can and cannot be done; it's more of a likelihood of programmer error thing. C++ has issues too, mostly because of various odd syntactic decisions that were made, several of which stem from trying to make it backwards-compatible. Some of it is plain ugly :) But it sure as heck puts bread on my table without stressing my brain too much.
Now I find myself evaluating the new Java, and C#, which both add even more features and little reminders to programmers to avoid common programmer errors. D is not looking too shabby, though it doesn't have anything like the market strength of either new Java or C#. Personally I think they are all getting bloated, adding too many keywords and not simplifying and unifying things enough. Back in my university days me and a buddy started designing a language we called D-, but we stopped after we realized how much time it would take to actually make it happen. I still dabble with the design on my spare cycles. Maybe some day... just maybe...
Re:More Confusion (Score:3, Insightful)
If your company refuses to hire people who refer to C/C++, then your company must not know what C++ is. If it did, it would a) Know that C++ is essentially a superset of C and therefore it is intelligent to make statements that apply to the dual entity referred to generally as "C/C++"; and b) You would have some kind of concept of class inclusion, and be able to understand that C and C++ are part of the sa
Re:More Confusion (Score:5, Insightful)
C++? (Score:5, Funny)
Re:C++? (Score:3, Funny)
Re:C++? (Score:3, Funny)
I can imagine a post to usenet now...
And the ensuing reply...
Re:C++? (Score:3, Interesting)
Alright!! (Score:5, Funny)
I'm sure the kernel developers will LOVE the idea of putting C++ in the kernel.
Re:Alright!! (Score:5, Insightful)
All you need is policy that covers use of various features, just like the Linux kernel requires policy on use of C.
multiple platform support becomes template specialisation, locking rules can actually be enforced by the language (ie, to get member functions to access an object, you can require that you call a member function to return a mutex object which has the members, and when that mutex is destroyed naturally, the lock is freed. fast, safe, secure.
The question is how customisable is the compiler for how virtual functions, etc, are implemented. Those are the only issues to be concerned about because C++ is plain better than C.
Re:Alright!! (Score:5, Funny)
Re:Alright!! (Score:5, Informative)
Although the idea that C++ compiled object code is bloated is incorrect. It's normally either due to inexperience with the language or due to a poor compiler implementation. Part of the problem is that on old compilers, template instatiations were actually included once for every object file that refered to one. More recent compilers can identify and remove duplicates at link time, or can save templates in a separate file and link it in at the end of the build. (For some templates, though, you can actually be better off with one in each file if each file uses inline member functions, and each uses a different one).
Sure C++ has it's faults, but bloatedness is not one of them - although a standard library may be bloated, but that's not an issue for the kernel.
Re:Alright!! (Score:4, Insightful)
Any language only goes so far, the thing that determines whether a software development project succeeds or not is policy and attitude.
For example, you can prevent changes in the apparent behaviour of the language by prohibiting operator overloading, template specialisation, and implicit constructors. Oh yeah, banning macros, which you also have the problem with in C.
And you don't have to worry about unexpected exceptions, because even if you didn't try-catch, the compiler cleans up *all* your objects in *every* case and tells the function that called you that you failed, and "here's why". The only reason you need to know about exceptions being thrown is to clean up resources and data-structures - and that is done in the destructors for auto class variables, so no problem there.
Re:Alright!! (Score:5, Interesting)
This breaks, and is very hard to debug by code inspection or by kdb. It is resolved by policy ensuring that the namespace for symbols/types/structs doesn't meet with the namespace for preprocessor macro's except for possibly a few agreed core macro's.
And it is similar policy that keeps C++ code safe.
Regarding your comment on the locking order. You make my point very well, in C, you have to manage locking order *at*every*call*point*, in C++ you can manage it where the locks are defined. So you make rules like lock A cannot be taken if lock B is already held. In C you have to make this just policy, in C++ you can do some neat code for these cases )though I'm not going to think it through now) that, depending on situation will BUG at runtime or even flat out refuse to compile. And to the user at the call point, it's just a lock.
As to memory management, I didn't explain memory management in the kernel, so I don't understand how I could have explained it naively. There is not just a small amount of non-paged memory allocated ahead of time. Anytime you need to be able to handle an error, you ensure (before the error can occur) that you have memory in which you can store intermediate data in the process of handling the error - otherwise you are dead in the water. Other than that, memory can be allocated within the kernel via a number of means, including kmalloc and the slab allocator. As to IRQ levels, I have an old first year OS and hardware architecture design textbook that discusses them (by a different name - so I could be misunderstanding what you mean), but that is in non-monolithic designs. I am not familiar with whether allocation is permitted in hard IRQ context in Linux or, if it is, by which of the available mechanisms, but if it is not permitted the hardirq *must* have the memory available to handle the error - whether it is C or C++. Throwing an exception in C++ does not require using any memory: in throw SomeException(blah), sizeof SomeException can be 0, and it can store it's information in the preallocated memory for that instance of the IRQ handler (which can of course be an object). If the C++ implementation doesn't allocate memory that it needs for trundling up the stack ahead of time then that is a Quality of Implementation issue, and different exception handling code is required but C++ is still acceptable.
And my notion of an exception is not naive at all. In well written code, when an exception is caught all objects in the try block are destroyed, and the data they represent goes with them so the destructor *does* whatever else is required for the state and change of state that it stands for. In C you have no choice but to try to remember everything in each error case (or use goto's to the one place - but then that's just like a low-feature exception with no compiler support for enforcing policy). Maintaining an understood state for the system is done by encapsulating things in objects and using destructors to handle keeping everything consistent.
All cleanup due to error occurs in one or both of two places: The destructors and the catch blocks. Mostly in the destructors. And you don't *randomly* clean up everything you can think of in C++, that's what you do in C. In C++ you rigourously clean up everything, whether you could think of it or not, because the compiler knows it's there. In the kernel an unknown error )whether by exception in C++, or error code in C) *must* be understood or passed on up the call stack until either something knows what to do, or the whole operation is abandoned for better or worse. In C, that is a lot of work and checking everything, in C++ it's virtually guaranteed.
Re:Alright!! (Score:4, Insightful)
That's wrong, too. There is no way you can change the meaning of e.g. int i=3+4; in C++. Of course there are things where you can change the meaning, but that's no different to the following statement about C: "every function call might be changed from what the author has intended (and tested) when somebody changed the definitions of what that function calls."
Clearly if anything you inherit from changes semantics, then this is a break of interface, just as changing semantics of a function is a break of interface. You shouldn't be surprised that if you use a library which does not conform to the specification your program expects then your program breaks. That's independent from language, coding style, programming paradigm, it's even independent from programming (e.g. if you think "moron" is something positive, then telling someone a moron will surely not have the effect you expected).
Re:Alright!! (Score:4, Interesting)
When an exception occurs, it must be caught and handled correctly (or propagated if that is appropriate) - just the same as a C error code returned from a function, so no loss there. As an advantage, an exception follows a distinct error path back up the stack frames so an error code is *never* treated like a value - which can spell a horrible death for both your uptime and data.
Within a syscall in process context, an uncaught exception will propagate up and up and up until it reaches a catchall at the syscall entrypoint, which can return an error to user-space without *any* harm to the kernel (provided the code is structured not to leave inconsistent state - but you have precisely the same issue in C, and C++ exceptions actually make it *easy* to clean up the state as you fall back through the stack frames).
Within a hardirq handler, the interrupt vector points to a similar catchall - the issue here is that timer interrupts (until the scheduler becomes tickless) and interrupts notifying of readiness by hardware can be missed, but only if you haven't handed off to a softirq or queued data for processing by a kernel thread. The C symptom of incorrect code is again different - the code carries on with incorrect data and balls' everything up in C, in C++ it gives up and leaves everything in a good state - unless the hardware *requires* servicing, but then your code simply has to be correct whatever language it is.
Within a kernel thread, the entry function will have a catchall that kills the thread and a monitor waiting for it's death can see it, log it and restart. Or you can write the code correctly as you have to with the C version (because if you write incorrect C code, the code carries on with bad data and balls' everything up).
So C++ can actually make the system *more* robust, not less. In particular - the raising of an exception does not kill the system except for rare cases where the calling function *also* doesn't bother to catch errors - and then some bug in a destructor prevents returning the state to how it was ! Which will kill your system in C too (or worse - corrupt data which is *far* less likely with exceptions).
C code has the added policy issue of clearing up resources on error. Since you often have at least two return paths, resource release code *must* be put into each and synchronised. This is precisely what exceptions do best - automatically nonetheless.
Yay! (Score:3, Insightful)
Re:Yay! (Score:5, Informative)
If you think it's OK, you obviously haven't been involved in kernel or embedded development. If you say one should be careful what features of C++ he uses and not to use this and that, I say one should learn proper C skills instead.
Re:Yay! (Score:5, Insightful)
Anyone writing a == b should notice that a & b aren't primitive types.
Re:Yay! (Score:3, Insightful)
Go fork your own kernel then. Good luck.
Re:Yay! (Score:5, Insightful)
Unless I misunderstood when I RTFA, that is exactly what the authors intend to do. And I, too, would like to wish them "Good luck." Linus obviously believes that C++ in the kernel is undesirable, but we'll never find out for sure until somebody like these people have the guts to actually try it, and the persistence to maintain a current patchset (or fork) long enough for the idea to catch on.
Re:Yay! (Score:3, Funny)
Made you look in header
Agreed about developers though, however the number of
those who have a clue is drastically lower than those
who think they have a clue. Everyone's a freaking C++
senior these days.
C++ in embedded applications is a bad idea (Score:4, Insightful)
Embedded dev is now often C++ based.
Too bad too. I am developing FAA Level A avionics software using C++, I am sorry to say. What a debocle. For starters, the compilers for non-gcc supported platforms uniformly suck. Typical compilers for DSP's lag the C++ standard by 10 years, and crash frequently. And my project is proof that if a language feature exists it will be used, no matter how pointless. For example:
or
Gross. Please keep C++ out of the Linux kernel!
C++ is a bad idea for bad programmers (Score:5, Insightful)
> Register_set regset(base_address);
> regset.write(SOMEREG_OFFSET , Register_set::BIT_A | Register_set::BIT_B);
Only a complete novice would write code like this. Your code setting *SOMEREG_ptr = BIT_A | BIT_B will work just fine in C++ too. In fact, you could transparently support multiple types of registers by overloading operator= of SOMEREG_ptr, which could be a polymorphic class. And if you think that is going to bloat your code, you obviously have never looked at the output of a good compiler like gcc. A good C++ design is FAR more readable than any C hack you can come up with.
> Typical compilers for DSP's lag the C++ standard by 10 years
That is the problem of your compiler, not the language. Stop bashing C++ when you should be blaming your vendor for not being able to write a decent compiler, or even port gcc to their platform.
Re:Yay! (Score:4, Insightful)
Only if you've overloaded operator==. But in that case, this is just a function call. A function call in C could just as easily add a few KB. The only difference between the languages here is that C++ gives you the "syntactic sugar" option of creating functions with the same names as operators. You can choose not to do that if you perfer and just use a regular function name, as in C. In no way does the ability to create a function named "==" instead of "Equals" show any more "lack of control" over code size than in C (exceptions might have been a better example).
Re:Yay! (Score:5, Informative)
In fact, eCos, a very nice (GPL) embedded operating system has its kernel written in C++. eCos performs well and is cleaner than a competing straight C RTOS which has to build its object system by hand (VxWorks' WIND kernel).
The real difficulty in using C++ for embedded development comes from the toolchains themselvs. Frequently new processor architectures don't have very functional C++ back ends but C is somewhat stable.
In fact, I worked on porting some C++ TV middleware to a specialized "media DSP processor." The GCC back-end for C was rock solid but C++ constructs would give me constant ICEs.
C++ does fix some dumb things in C, but when it comes to shooting yourself in the foot, C++ is like an AK-47 while C is more like a
Re:Yay! (Score:3, Funny)
This should be good news to the NRA's development division...
Stillborn. Seriously (Score:3, Funny)
Or better yet - Brainf*ck, my personal favourite
Great news, I hop (Score:4, Interesting)
It'd sure be nice though...
RMS (Score:5, Funny)
Re:RMS (Score:4, Funny)
Progress (Score:5, Interesting)
Anyway, this is a neat hack and I look forward to seeing what comes of it.
Re:Progress (Score:4, Informative)
The simple reason for that is that otherwise the kernel would be unpredictable. Let's say the error logging function used the string class (which likes to allocate memory behind your back). If the memory allocation function fails and tries to print an error message... you got yourself a kernel crash. This is why the kernel is significantly more difficult to program than, say, a word processor.
Re:Progress (Score:5, Insightful)
Yeah, who wants a common driver API for video, network, or sound cards...
Not to mention that drivers are all about abstracting the hardware and interface implementation from the OS itself anyway...
The simple reason for that is that otherwise the kernel would be unpredictable. Let's say the error logging function used the string class (which likes to allocate memory behind your back). If the memory allocation function fails and tries to print an error message... you got yourself a kernel crash. This is why the kernel is significantly more difficult to program than, say, a word processor.
Yes, a kernel is more difficult than a word processor, but that doesn't mean that implementors must implement stupid C++ code. You can do some pretty neat things in C++ if you know what you are doing. If you don't know what you are doing, you can do some pretty crappy things.
Re:Progress (Score:3, Informative)
Yes, a kernel is more difficult than a word processor, but that doesn't mean that implementors must implement stupid C++ code.
No, the problem is not if it's difficult or not, is the fact that C++ implies the existence of an intrinsic memory management behaviour (new/delete), that is not really compatible with the strict memory management a kernel must implement.
Re:Progress (Score:5, Insightful)
That got a chuckle from me. I know what you meant, but after looking at the following (randomly chosen
if ((((u ^ v) & (v ^ w)) >> 1) & ~(u | v | w) & 1) {
if (i == 20) {
crc = buf ^ (buf >> 7) ^ (buf >> 14);
if (!((crc ^ (0x25cb9e70 >> ((crc >> 2) & 0x1c))) & 0xf)) {
data[buf >> 18] = buf >> 4;
status |= 1 > 18);
}
The simple reason for that is that otherwise the kernel would be unpredictable.
Point taken, but I hope you're open to the idea that C++ classes can be written that avoid these problems. In particular, it's relatively easy to define your own memory management scheme. This could be confusing to some (redefinition of new and delete would not be obvious in other parts of the code), but C++ has some nice features that facilitate scalability. I'm sure you'll agree that maintaining such a complicated thing as a cross-platform kernel can use some more sophisticated tools for software development than what C provides.
Re:Progress (Score:5, Insightful)
Complex code becomes predictable by building layered abstractions with well-defined interfaces. C++ supports that better than C.
Let's say the error logging function used the string class (which likes to allocate memory behind your back).
The kernel almost certainly wouldn't be using "the" string class, but its own string class, adapted specifically to the needs of the kernel. Right now, the C-based kernel doesn't use the user mode C library either, after all.
If the memory allocation function fails and tries to print an error message... you got yourself a kernel crash.
Quite to the contrary. Not only would the kernel not crash, with a properly designed string class, out of memory conditions would actually be guaranteed to be handled correctly in all string operations everywhere in the kernel. No more case-by-case checking and handling of whether the memory allocation happened to succeed this time or not. In this particular case, the string class would throw an out-of-memory exception in the error handler and the stack would unwind up to the point where there is a handler.
Furthermore, the error logging function can decide to intercept such exceptions and print an emergency error message on the console, and it can do so reliably without ever having to worry about checking a single status or return value.
Altogether, this is a big improvement over C-based handling of such situations. But if you want to keep this situation from occurring in the first place, there is no more reason for the error logging function to allocate memory in C++ than there is for it to do so in C.
Re:Progress (Score:3, Insightful)
It's not so much that C++ itself is so bloated etc. but that some of the common C++ programming idioms - full of templates, overloading, deeply nested class hierarchies with virtual methods, etc. - can lead to bloat. It's never good to have what looks like a simple assignment statement turn into thousands or even tens of thousands of instructions, but it's particularly dangerous in the kernel. Templates are particularly bad because they get re-instantiated for every type they're used with and that can ver
Sorry to break it to you... (Score:3, Informative)
But I'll shut up. I've pretty much turned my back on C and C++ anyway.
Who cares? (Score:5, Informative)
In fact, in Linux we did try C++ once already, back in 1992.
It sucks. Trust me - writing kernel code in C++ is a BLOODY STUPID IDEA.
The fact is, C++ compilers are not trustworthy. They were even worse in 1992, but some fundamental facts haven't changed:
* the whole C++ exception handling thing is fundamentally broken. It's _especially_ broken for kernels.
* any compiler or language that likes to hide things like memory allocations behind your back just isn't a good choice for a kernel.
* you can write object-oriented code (useful for filesystems etc) in C, _without_ the crap that is C++.
In general, I'd say that anybody who designs his kernel modules for C++ is either
* (a) looking for problems
* (b) a C++ bigot that can't see what he is writing is really just C anyway
* (c) was given an assignment in CS class to do so.
Feel free to make up (d).
Re:Who cares? (Score:3, Interesting)
I am all for the kernel remaining C forever, but just for the sake of curiosity's fancies, I wonder how much better Objective-C would be as a high level yet still high performance solution as opposed to the messier C++?
"The fact is..." he's out of touch (Score:3, Interesting)
Anyone who claims with a straight face in 2004 that "C++ compilers are untrustworthy" is trolling. Sorry, rabid penguin lovers.
I love it when language bigots forestall any reasonable discussion by preemptively accusing anyone who disagrees with them of being a language bigot. Slashdot, of course, believe that Linus can do no wrong, so none of it ever applies to him...
After having conversations with him myself, I can state my honest belief that Linus doesn't understand how to use C++, and will simply
Re:"The fact is..." he's out of touch (Score:3, Interesting)
The fact is that in the kernel much of the low level code cares about the exact physical layout of memory, and if it were mostly C++ you would need more parts in assembly which must be ported to each archatecture.
Yes, C can be used in a higher level, but you are calling functions that deal with the low level from there is a very much OO way.
Also
Re:Who cares? (Score:5, Insightful)
Please people, I know Linus is God, and I have a lot of respect for the man. But I don't care who it is, if people make statements like this, I'd like to see some back up.
It sucks. Trust me - writing kernel code in C++ is a BLOODY STUPID IDEA.
When someone says 'trust me' it either means "I'm too lazy to explain" or "I haven't really got something to prove it".
The fact is, C++ compilers are not trustworthy. They were even worse in 1992, but some fundamental facts haven't changed:
Well, I don't want to start a flamewar here, but while this may be true for the GNU compiler, it certainly is NOT true for, for example, the Microsoft compiler. (I know, how dare I say that...) It has produced code from C++ source for a _very_ long time and even the optimizer works very well.
* the whole C++ exception handling thing is fundamentally broken.
Why?
It's _especially_ broken for kernels.
Why? Maybe for the Linux kernel, because it wasn't designed with C++ exceptions in mind. And I'm not even say that that's bad, but why is it in gerenal broken for kernels?
* any compiler or language that likes to hide things like memory allocations behind your back just isn't a good choice for a kernel.
Well, that's really implementation and as such is your choice, it's not the language. Furthermore, no-one forces you to use _all_ possible language features. I personally stay away from many C++ language features such as overloaded operators.
* you can write object-oriented code (useful for filesystems etc) in C, _without_ the crap that is C++.
But why would you if you can do it cleaner in C++ and have the compiler generate the same quality code? What is crap about C++?
What Linus needs to do is go back to the old days where he looked at assembly output. I still do that and have compared C++ with C many times and I can't see why anyone would not use C++.
You don't have to use all the bells and whistles, shit, you can write plain ANSI-C and still use a C++ compiler for it's superior type checking etc.
Anyways, to each his own, I guess...
(d) There's a big fat hole in the standard. (Score:3, Interesting)
If a member object's constructor, or a routine it calls, somehow gets hold of a pointer to the containing object and calls a virtual function, IMHO it should be performing a legal operation and should get the BASE CLASS version of the function. Ditto in the destructor. (At this stage of construction the base class is fully functional, while the derived class is
Re:(d) There's a big fat hole in the standard. (Score:3, Interesting)
(Or overridden functions in general, whether virtual or not.)
Re:Who cares? (Score:5, Informative)
The second- C++ has hidden allocations all over. In C, its easy to find memory allocations. Grep for malloc (or kmalloc in the kernel). In C++, you have temporary objects being instantiated all over the place, automatic constructors/destructors being called, etc. Its nowhere near as open or easy to find (especially temporary object creation. If you don't think thats a problem- try putting a cout statement in a constructor, and write a function that takes an object as a parameter and returns that object. Count how many you see. Its more than 1.) Its not as clean. While this may be tolerated (although confusing) for an application, for a kernel its murder. Memory is tight, and mallocing will kill you performance wise if you need to grab a new free page. It may not even be possible to do if interrupts are locked. Its a hassle.
In fact, a lot of embedded project don't even allow dynamic memory. I design printer firmware. We are not allowed to call malloc. All memory is tightly controlled by thesystem and is strictly deterministic to ensure we can always do a job. A large amount of object creation doesn't make sense in an embedded/kernel environment.
Third- why not? There's places where its the best tool fro the job. Assembly gets a bad rap, really its a nice simple language. The real question is- what does C++ give you that C doesn't? Objects- C has them. Inheretance? Very rarely does it really benefit you, its usually used because "we're OO, we're supposed to use it". Templates? Ok, those can be useful for things like linked lists, although the STL goes way over the top with it. Exceptions? See above. The gains of C++ are minimal, the pain of it is large.
Re:Who cares? (Score:5, Insightful)
Don't like exceptions? Don't use them. C++ doesn't require you to. Personally, I don't use them unless I have to interface with other code that does. I usually compile with exception support off.
Is allocating memory in a constructor likely to cause problems? Make it a standard code practice for your project to never cause non-explicit memory allocation. Destructors can be forced to run at a specific time with delete or by using forced scopes (use {} around the lifetime of the local var). Copying objects in a standard way is easy to do, espescially if you always pass classes (structs) as references or by pointer. Are you saying that C++ always uses more memory than C? That's silly. If you can't call memory allocation functions right now, then allocate things on the stack. Make sure that the objects you create and the functions you call don't alloc either. You would have to make sure the functions were safe in C too. Ok, so don't use the heap. There is no reason that C++ needs to use the heap; everything can be allocated on the stack. Just like C. Assembly isn't too nice if you care about portability. It also depends on the architecture about how nice and simple it is. Segmented memory in assembly can be a nightmare.
Don't use the STL implementation of linked lists if you don't like it. Done properly, you could use templates for even more than that, like different index sizes for a filesystem; a 32 bit version for small volumes, a 64 for large volumes and a 128 for extremely large volumes. Since there is no primitive 128 bit type, C++ lets you override operators to create a new type that acts exactly like a primitive. This word size would be a template parameter of the filesystem class; a static version created for 32, 48, 64 and 128 bit or whatever. One code set, no redundancy. Remember the Sun story about a 128 bit filesystem? It could be as easy as recompilation!
How about namespaces? These would be very useful in the kernel, IMHO.
Member functions are nice for associating a function with an object.
Private data members allow you to put data in a structure that outside code doesn't need to know about so you can change it later without breaking compatibility. Documentation can do it too, but this can enforce it.
I bet there could be some good uses for smart pointers.
The fact that a language has a feature does not obligate you to use it. You can use code standards in your project that set sane regulations for the code in the project. You need standards for any a sizable project in ANY language, including C. I'm sure that the Linux kernel already has rules as to naming conventions, header file control etc... More could be created to regulate good usage of C++ in a kernel environment.
Re:Who cares? (Score:3, Insightful)
fantastic ... (Score:4, Funny)
i can't wait to try and debug virtual functions, copy constructors, and polymorphism over JTAG or BDM!!!!
man thats gonna be fun
i always found C causes to much clutter in the linux kernel
keep an eye for this in 3.0
Jim
C++ (Score:5, Interesting)
I'm not sure if many people remember, but there was a short time when the kernel source was compiled with g++, even though the source was plain C.
IIRC (memeory very hazy, though), it lasted about a month in 1992 or 1993, and it had something to do with type-safe linking(?).
Re:C++ (Score:3, Funny)
Here's what's coming up! (Score:4, Funny)
Exception-handling changes relevant for g++? (Score:4, Interesting)
Would they be applicable to the user-space runtime?
interesting, but not very useful (Score:5, Interesting)
In fact, there was a good post on kerneltrap not to long ago about C++ inside the linux kernel:
http://kerneltrap.org/node/view/2067
Worth a read if you've got a few minutes to burn.
Re:interesting, but not very useful (Score:3, Informative)
The true nature of C++ :) (Score:5, Interesting)
I think trying to incorporate C++ into Linux kernel is a good decision, giving more vitality to Linux and allowing it to differentiate better from the traditional UNIX systems - but that's only my 0.02 Euro.
But why should C++ be used in the Linux kernel? (Score:3, Interesting)
You're going to kill Stallman (Score:3, Funny)
Reviving a joke... (Score:3, Funny)
Oh god, WHY? (Score:3, Interesting)
Don't get me wrong, C++ is an OK language, but I'd think twice before using its exceptions.
C++ in the kernel? (Score:4, Insightful)
The value of an OO language in larger projects is enormous. Basically there are simply too many things that could go wrong at any point, and the overhead associated with C++ (memory use, exception setup, excess copying, dynamic checking) is a small price to pay for the additional benefits it provides. As you get closer to the metal though, and you have to watch what you are doing more closely. You want to know exactly when memory is being allocated, when something may go wrong, and only want to set up to catch exceptional circumstances if you know they may occur. Resources in kernel-land are expensive. C allows this kind of control, C++ does not.
My former boss would love to see me defending C over C++ like this. The irony.
Having said that, the capability to run C++ code in the kernel would certainly be nice, provided it didn't impact the existing code. I'm not sure how this one could be pulled off though. There'd be too much code that would need to be made aware of exceptions, destructors, so forth.
call/cc (Score:3)
Re:call/cc (Score:5, Funny)
Once you've done all this, Linux will truly be ready for the desktop. (Assuming you axiomatize your language definition first, to get rid of unnecessary features like for loops).
Linus and C++ in the kernel (Score:5, Informative)
C vs C++ (Score:4, Insightful)
Personally, I think mixing C++ into the kernel is not a good idea, generally, in my experience certain aspects of C++ are messy to debug, and if you're gonna skip using them, then perhaps you should've stuck to C.
Also these guys used to distribute their pronto project in one tarball, a modified version of the Linux kernel, and the website for downloading it made you have to accept *their* license. When the issue of whether this was possibly in violation of the GPL, and if they should rather distribute a clean patch, came up on the local GLUG mailing list (www.rglug.org) their response was rather shocking, they absolutely refused to acknowledge that they should perhaps distribute their code in another way, and even reverted to speculations about the legitimacy and enforcability of the GPL. To their defense, the original 'article' on the matter was very inflammatory and made some rather derogatory remarks, and IIRC they changed their website some time later.
Multicasting is a cool technology, and dynamic multicasting routers such as RU is researching and developing with the Pronto project, may well be the key to using the internet as a single infrastructure for 95% of our content-delivery and communication needs (digital TV through the internet, without exponentially increasing bandwidth load, etc), so I hope RU keep on, and their work be fruitful
Also, to everyone who refers to the creator of Linux, as 'Linux'... his name is 'Linus', get it through your heads, this is slashdot.org not mouthbreathers.org
Exceptional programming (Score:4, Interesting)
When I say "thread" above I'm not just throwing around an ad hoc term -- you can use this to provide the basis for parallel execution in an OS or language.
There is an entire school of thought built around this idea called logic programming and it is based on the most widely used foundation for mathematics -- the predicate calculus.
I don't know why people spend so much time and energy optimizing things that are less powerful.
As for object oriented programming, As I've said before [slashdot.org]:
Almost all the Object Oriented stuff people layer on predicates are, at best, an ad hoc, and poor, means of optimizing execution speed.
Let me explain.
One of the principles of polymorphism is that the same method has the same abstract meaning regardless of the kind of object. A predicate considered as a method subsumes such polymorphism by simply trying the various possible implementations of the method and committing to only those that succeed. If more than one succeeds then so be it -- that's the whole idea of relations as opposed to functions.
So, one reason you want all this OO stuff is the inheritance hierarchies keep you from going through all possible interpretations of a given method when the vast majority of them will fail for a given object.
Another, related, problem is that inheritance provides defaults without requiring a lot of thinking on the part of the computer. What I mean by "thinking" here is the sort of thing that is done by statistical imputation of missing data via algorithms like expectation maximization (EM) [clusty.com] [clusty.com] or multi-relational data mining [clusty.com] via inductive logic programming [clusty.com] .
So, the other reason you want all this OO stuff is so you can avoid mining a background database to provide reasonable defaults for various aspects of the data.
Some might be concerned that over-riding isn't absolute in such a system -- that you don't absolutely block, say, more generic methods when you have more specific ones present, and they're right. You don't block those methods -- you lower their priority by lowering the probability of those implementations via the statistical methods of imputation and/or induction. In a microthreading environment they most likely won't get any resources allocated to them before other higher priority implementations have succeeded. In a single threaded/depth-first environment they will be down the list of desired alternatives -- but they won't be discarded until something equivalent to a prolog cut operation kills them off.
However, and this is the important point, the work that has been expended toward OO facilities has vastly outstripped the effort that which has been put toward more parsimonious ways of optimizing predicate systems.
One of the better predicate calculus systems out there -- more promising due to its use of tabling to avoid infinite regress on head-recursive definitions and its optimization of queries using some fairly general theorems of predicate calculus -- is XSB [sourceforge.net] . It has an interface to odbc and a direct interface to Oracle, but it would be better if it had something like a
Shapiro's take on this (Score:4, Interesting)
EROS was originally implemented in C++, but then
it was reimplemented in C [iu.edu].
I take exception... (Score:5, Informative)
I've only written one linux driver, so I'm no expert, but I can think of situations where exceptions can be helpful for device drivers.
Take, for example, a game controller or other hardware device that can become unplugged at any moment. It's useful to have an elegant way of handling this uncommon occurrence.
Exceptions are a useful way to separate uncommon sanity checks from the rest of your code, so you're not forced to use ugly nested conditionals.
Re:Exceptions are suddenly viable? (Score:5, Informative)
If exceptions were never meant to be thrown, they wouldn't be in the language. Exceptions are an abstraction for dealing with exceptional conditions -- conditions that do not normally occur, but can occur. At the expense of some additional complexity, they make error checking a little simpler and less bug-prone. When (not if -- assuming you are a believer in Murphy's law) those exceptional conditions occur, your program better be able to handle them correctly.
You are right that some people do use exceptions when not appropriate. Exceptions are (generally) not appropriate for exiting loops, for example. But they are more than appropriate for out of memory conditions, out of disk space conditions, etc.
The reason they are not viable performance-wise is not because they are too expensive to throw; it is because they are too expensive when they are never thrown at all. There's generally a 5-10% performance hit just from having code that might possibly throw an exception, depending on your compiler's implementation. The numbers on the netlab page are for throwing exceptions, unfortunately; I would be interested in seeing if they got a performance benefit when exceptions are not thrown. Guess I'll have to dig to find a copy of the paper.
Re:Exceptions are suddenly viable? (Score:4, Interesting)
FWIW, I believe modern compilers now approach the zero-overhead ideal for exceptions when they aren't thrown, and have done for a little time now. Several people directly involved have posted to this effect on the major C++ newsgroups in the past.
Re:Exceptions are suddenly viable? (Score:3, Interesting)
It's ridiculous that this comment is modded up to +5 Insightful.
Would you care to back up this claim with something tangible?
Of course the word 'never' is totally inappropriate since by definition exceptions _are_ designed to be thrown.
The only valid thing in your comment is that certain programmers over-use exceptions. Then again, certain programmers also do stuff like #define forever for(;;). That to me is o
Re:Exceptions are suddenly viable? (Score:5, Informative)
Classic example: a method calls another that calls another that calls openfile() for a temp file, which fails. the lower two methods don't care, and the toplevel one can give the user a proper error message and clean up.
People wonder why software is so hard to test, does so poorly on error handling, yet complain whenever we add mechanisms to languages to help.
Re:Exceptions are suddenly viable? (Score:4, Insightful)
> Obviously an unsuccessful operation.
Well, you want to communicate back to the higher level code *why* the call failed.
Oh, wait, no problem!
Well set a global variable called errno.
Oh yes, and scratch our heads for a seeming eternity while we figure out exactly how to virtualize different errnos for each thread.
And hope to hell that no failing system calls get called between when we failed and when the user checks errno.
Rock on!
Re:Exceptions are suddenly viable? (Score:3, Informative)
they're an in-language mechanism similar to signals, only that they don't have the brain-deadedness of them.
Hell, just having smart pointers whose destructors are properly called on the stack unwind is enough.
That's not what exceptions are for... (Score:5, Insightful)
Sorry, but I think you're missing the point of exceptions. They are supposed to decouple generating the error from reacting to it, because in practice that's often useful.
Exceptions are a systematic way to return control multiple layers up the code, without cluttering the code in between passing information it doesn't need to know or care about. They are best used where the code that directly causes the error can't handle it because it doesn't know how, and the code that handles it doesn't care where it came from, because the code that was trying to run aborted anyway.
You could write at least a good length article on what exceptions are and aren't good for, but in short, if you ever throw exceptions exclusively at one level and catch them exclusively at the next level up, there's a good chance you're using the wrong tool for the wrong job.
Re:That's not what exceptions are for... (Score:4, Informative)
int addclient(int s,struct sockpair *sp)
{
struct sockaddr_in sin;
socklen_t sl;
int local,remote;
sl = sizeof (struct sockaddr_in);
if (-1 == (local = accept(s,(struct sockaddr *)&sin,&sl))) {
perror("accept()");
goto just_return;
}
fcntl(local,F_SETFL,O_NONBLOCK);
if (extent >= TCPFWD_NO) {
fprintf(stderr,"error: out of buckets! %u >= %u\n",extent,TCPFWD_NO);
goto close_local;
}
if (-1 == (remote = socket(PF_INET,SOCK_STREAM,0))) {
perror("socket()");
goto close_local;
}
memset(&sin,0,sizeof (struct sockaddr));
sin.sin_family = AF_INET;
sin.sin_port = htons(remote_port);
sin.sin_addr.s_addr = inet_addr(remote_addr);
if (INADDR_NONE == sin.sin_addr.s_addr) {
fprintf(stderr,"inet_addr('%s'): failed\n",remote_addr);
goto close_remote_local;
}
if (-1 == connect(remote,(struct sockaddr *)&sin,
sizeof (struct sockaddr_in))) {
perror("connect()");
goto close_remote_local;
}
fcntl(remote,F_SETFL,O_NONBLOCK);
sp[extent].allocated = 1;
sp[extent].a = local;
sp[extent].b = remote;
extent++;
return 0;
close_remote_local:
close(remote);
close_local:
close(local);
just_return:
return -1;
}
Re:Exceptions are suddenly viable? (Score:3, Informative)
Re:Exceptions are suddenly viable? (Score:4, Insightful)
You can senselessly dump all your error handling code in the middle of nowhere using return-value error codes, too, if you really want to.
Re:Exceptions are suddenly viable? (Score:5, Insightful)
Exceptions in the kernel are inherently a bad idea. An uncaught exception is a kernel panic. By contrast, an unknown error return is still an error, and usually the right thing happens. The risk of allowing exceptions in the kernel far outweighs any possible benefit. That's why nearly every kernel that has ever used C++ at any level has explicitly excluded exceptions. (That and the very nature of exceptions inherently results in worse performance than using error returns. In the kernel, performance is far more important than facilitating programmer laziness. :-)
It would be wise for the Linux community to learn from other OSes that have tried to do kernel exceptions. Even the Windows kernel developers rejected them as a bad idea. Don't do it. Don't accept any patch that allows it.
Re:Exceptions are suddenly viable? (Score:4, Funny)
MS Developer #1: I was thinking we could put exceptions in the kernel.
MS Developer #2: Are you insane? Why on earth would you want to do that? I don't think I've heard a stupider suggestion for a kernel addition.
MS Developer #1: Really? Well uhh... how about we put an Internet browser in the kernel?
MS Developer #2: FREAKIN BRILLIANT, let me call Bill.
- sm
Re:Exceptions are suddenly viable? (Score:4, Insightful)
The whole point of exceptions is that you don't care. If you care about each specific read, you wrap each read in it's own block (the same as error conditions, except that you'd use an if block).
Whats the state of all your objects?
This is why object-oriented C++ is so wonderful and Java is so bad - your objects are automagically in the correct state because you allocate and clean up resources in thier destructors. If an object is in scope, it's in a clean state. If it's not in scope, it's not. You can write some really concise, clean, reliable code using this concept - it's where the true power of objects comes into play. In C, you have to manually check EVERY call and clean up EVERY resource - it's very susceptible to programmer error, especially in deeply nested call chains with gotos and whatnot all over the place (like the Linux kernel, for example). In Java, which doesn't have destructors, it's even worse because you've got exceptions with no automatic cleanup, which means you've got to have all sorts of ugly nested try/catch/finally and state management.
Exceptions are a nice way of dealing with problems, especially nested calls. But combined with destructors, they're a magnificent way of keeping error handling safe.
People use goto in C because they want a nice exit point in the case of failure. People use exceptions for exactly the same reason - it simplifies error handling. It's true that it's physically seperate from the code, but on the other hand it's within the same block so you've got a visual/indendation indication at least. If you think exceptions are a maintainers nightmare, then you've never tried to fix an error in a function with 40 different exit points, with almost identical cleanup code at every point. A C programmer would use a goto so that there's not so much duplicate code and it's easier to maintain. A C++ programmer would use exceptions and automatic objects to do exactly the same thing, in roughly the same lines of code, with with even less (quite possible 0) duplicate code and greater modularity.
Re:Exceptions are suddenly viable? (Score:3, Informative)
Re:Great news! (Score:4, Insightful)
Now if you were to start a new kernel entirely in C++, that'd be fine. The use here would be to mix the two *shudder*. No thanks. You then have a problem where the C++ people can't understand the C code, and the C people don't understand the C++ code. Its a maintenance nightmare. Just wait til the first patch that requires changing C and C++ parts. It'll be ugly.
Its much better to pick 1 language for a project and stick with it, or do a total rewrite. Mixing the two will just cause problems. Luckily, this patch has near 0 chance of being taken into the kernel.
Re:Dumb Person... (Score:5, Insightful)
Essentially, C++ offers support for many, many different types of programming. Just like there are some tasks for which object-orientation is better than procedural, there are some projects for which generics are superior, for which functional programming is superior, etc., etc.
C++ is not an object-oriented language and was never intended to be (as reading Stroustrup will tell you); C++ was meant to support a broad variety of programming styles, of which object-oriented programming is just one.
So what do we gain by allowing the kernel to use C++? Mostly, we allow kernel programmers flexibility to solve problems in different ways. However, the trick to this is that while we're giving the programmers additional tools with which to do their jobs, we're giving them more complex tools which sometimes fail in extremely bad ways.
Exceptions are a good example. Up until very recently, code that used exceptions was about 5% slower than code that was exception-free. This five percent penalty was unavoidable overhead. Now, some people got bit by this five percent hit (usually people working in realtime fields) and came to the conclusion of "oh, C++ sucks for RTOS because exceptions give a five percent hit".
The reason why they came to that conclusion is easy to understand: it's easier to blame their tool than their knowledge of the tool. It's easy to say "oh, C++ sucks"; it's harder on the ego to say "well, I didn't know that about C++, and it bit me in the ass."
Many--and maybe most--people who condemn C++ have not used it recently. Linus, for instance, condemns C++ based on his experiences with it from 1992, six years before the C++ language had been standardized and ten years before GNU got a decent C++ compiler.
C++ is a very complex language, as anyone, even C++ aficionados, will tell you. On the other hand, in the hands of someone who's made the (significant) investment to become a skilled C++ programmer, C++ is capable of breathtaking power and elegance.
The conflict is essentially this: one side believes "if we add C++ support to the kernel, we'll have lots of incompetent C++ people doing all manner of incompetent C++ things which are really stupid and killing performance" and the other believes "with C++ support to the kernel, we give programmers different ways to solve approach problems, and I'm not going to deny all programmers the benefit of C++ just because many programmers can't use it effectively."
I sincerely think that adding C++ support to the kernel is a good idea, subject to some strict requirements. For instance, have a C++ Czar for the kernel, someone Linus trusts to have wisdom and understanding of C++; and make sure that all C++ checkins to the kernel go through the C++ Czar to ensure that C++ is being used wisely, and not as an impediment to understanding.