Follow Slashdot stories on Twitter

 



Forgot your password?
typodupeerror
×
Programming Operating Systems Software Technology Linux

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."
This discussion has been archived. No new comments can be posted.

C++ In The Linux kernel

Comments Filter:
  • by Anonymous Coward on Wednesday October 27, 2004 @05:51PM (#10647349)
    n/t
  • Great news, I hop (Score:4, Interesting)

    by Anonymous Coward on Wednesday October 27, 2004 @05:53PM (#10647371)
    That's really awesome news, but I just can't imagine it being accepted in the mainline branch. Many figureheads in the linux kernel group are anti-C++ enough to probably veto this effort. (If "anti" is too strong, then at least I'll safely claim they're not "pro C++".)

    It'd sure be nice though...
  • Progress (Score:5, Interesting)

    by caseih ( 160668 ) on Wednesday October 27, 2004 @05:54PM (#10647384)
    Say what you will about C++ being slower and more bloated than C, but I think this is a huge leap forward. I doubt Linus will accept it anytime soon as an official patch, though. If they have succeeded in making exceptions quick, I think C++ has a real place in the kernel. C++ offers the ability to have better type safety and more modular apis and interfaces to the kernel. For example being able to develop a new device driver inheriting from a nice base class is a good idea.

    Anyway, this is a neat hack and I look forward to seeing what comes of it.
  • by TheRain ( 67313 ) on Wednesday October 27, 2004 @06:00PM (#10647435) Homepage
    using the kernel now? :)

    Joking aside, this is cool. Runtime compiling makes conceptual sense in an open source operating system running mainly open source software... though it will surely add to load times. It adds to the openess of open source by keeping the source editable straight up untill run-time and, so, encourages keeping source code and editing source code... being that it is immedietly executable, given it was coded correctly of course ;)
  • C++ (Score:5, Interesting)

    by bsd4me ( 759597 ) on Wednesday October 27, 2004 @06:02PM (#10647455)

    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(?).

  • by Monkius ( 3888 ) on Wednesday October 27, 2004 @06:03PM (#10647468) Homepage
    Kernel aside, I wonder if G++ developers out there have any comments on these guys' exception-handling changes?

    Would they be applicable to the user-space runtime?
  • by cout ( 4249 ) <curlypaul924@g[ ]l.com ['mai' in gap]> on Wednesday October 27, 2004 @06:05PM (#10647487) Homepage
    Any kernel project that uses C++ is most likely doomed to be an experimental project and will most likely never be included in the kernel. IMO, there's good reason for that, too. The added complexity just doesn't outweigh the benefits of using C++ over C.

    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:Who cares? (Score:3, Interesting)

    by Kethinov ( 636034 ) on Wednesday October 27, 2004 @06:05PM (#10647492) Homepage Journal
    I agree entirely. C++ in the Linux kernel is a largely bad idea.

    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++?
  • Re:C++? (Score:2, Interesting)

    by Electroly ( 708000 ) on Wednesday October 27, 2004 @06:11PM (#10647554)
    Interestingly, the driver interface in Mac OS X actually is COM. With QueryInterface() and everything.
  • Re:Who cares? (Score:1, Interesting)

    by Anonymous Coward on Wednesday October 27, 2004 @06:14PM (#10647572)
    Fact is, its harder to write robust code in C than it is in C++.
    Fact is, we ain't in 1992 anymore. Our computers can take the miniscule slowdown compared to the better code.

    His point 1 is unproven.
    His point 2 is wtc? Was he thinking Java here?
    His point 3 has minimal validity; but still has lots of unproven sitting behind it.

    His point (a) is bigoted.
    His point (b) is bigoted.
    His point (c) is asinine.

    Haha! Now I'm a troll for dissing Linus!
  • by kompiluj ( 677438 ) on Wednesday October 27, 2004 @06:16PM (#10647595)
    C++ was designed to be the language of choice for modern operating systems, meant to replace C. This is main reason why every decision was made with efficiency in mind (no automatic virtual functions, no garbage collection, and, oh yes!, the infamous: pointers and goto). And of course C++ is fast. Maybe it loses by hair's breadth with C but surely wins with Java by great margin. And don't tell me about JIT, do some homework.
    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.
  • by devphil ( 51341 ) on Wednesday October 27, 2004 @06:19PM (#10647624) Homepage


    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 assert that "it's just C anyway" no matter how many times he's proven wrong. He's a smart guy, but he's got his blinders on in some respects.

  • by master_p ( 608214 ) on Wednesday October 27, 2004 @06:19PM (#10647628)
    The article says that they managed to support C++ in the kernel. Well, that's sweet as an accomplishment. But what are the benefits? many parts of the kernel are already object-oriented, in the form of manually written vtable structs and object structs that have pointers to those vtables. I just don't see a reason for C++ in the kernel. Maybe someone that knows more on this can enlighten us.
  • Oh god, WHY? (Score:3, Interesting)

    by melted ( 227442 ) on Wednesday October 27, 2004 @06:29PM (#10647701) Homepage
    Haven't they read "Exceptional C++"? C++ is a fucking disaster. It kind of constantly conspires against you to shoot you in the foot in some kind of massive manner where you'd least expect. Sure, non-exception enabled code is ugly (check the return values all the time, etc), but any non-trivial exception-enabled code is nearly impossible to write if the requirement is that it works correctly in all situations (which is what the requirement is for the kernel).

    Don't get me wrong, C++ is an OK language, but I'd think twice before using its exceptions.
  • by slashdot.org ( 321932 ) on Wednesday October 27, 2004 @06:36PM (#10647762) Homepage Journal
    oh dear, again someone who doesnt; understand that exceptiosn are designed never to be thrown.

    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 over-using #define. So should we rip the pre-processor out of the compiler because certain programmers use #define in a way that you don't fancy?

    Exceptions are extremely useful to write clean code with proper error handling. The truth is that because handing error conditions with return values is cumbersome and ugly, people often just don't implement error handling. Great.

    If they were everyday occurrences, then they wouldn't be, well, exceptional.

    I think it's perfectly normal and acceptable to have an exception be an everyday occurrence. There's nothing magical about exceptions that would justify saying that they should never be used. Sure, throwing an exception is a lot of overhead. So TF what? If you only do it in exceptional situations...

    To me the word 'exception' means to me, anything that happens that's not in the normal code path. The standard software flow should not use exceptions, but anything else is, well, exceptional.
  • by Anonymous Brave Guy ( 457657 ) on Wednesday October 27, 2004 @06:49PM (#10647909)
    There's generally a 5-10% performance hit just from having code that might possibly throw an exception, depending on your compiler's implementation.

    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:great! (Score:2, Interesting)

    by pyrrho ( 167252 ) on Wednesday October 27, 2004 @06:55PM (#10647972) Journal
    I'm a bit out of date on RTTI implmentations but I did see that mentioned, which sounds great. A pointer to what though?

    Anyway, RTTI can be a great thing (and beats building your own dynamic typing system when you need one) but I'm with Stroustrup that the need for one shows improper design in the most general case.

    btw, I love C++. The point is that C++ has many available paradigms and idioms available, this gets it a lot of teasing... but it's a strength... a project is to choose the idiom it prefers and stick with it.
  • by Ungrounded Lightning ( 62228 ) on Wednesday October 27, 2004 @07:27PM (#10648295) Journal
    My pet peve: the gaping hole in the standard regarding the use of virtual functions from constructors and destructors and routines that serve them.

    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 not yet initialized making attempts to call its version of the function massively broken.) Ditto during destruction. The derived class version should be the one you get beginning with the first line of the body code of the constructor and ending with the last line of the body code of the destructor. (The object transitions during those sections of code, which can be coded carefully to only use virtual member functions whose support is initialized.)

    Everywhere else C++ uses extreme care to get the "right" level of virtual function. (This is unlike Objective C and Smalltalk, which "get it wrong" big time by calling derived class (subclass) versions in base class (superclass) construction code, breaking the already-debugged code.) But here the standards - and the implementors - missed an imporatant point.

    With an opportunity for both construction and destruction code to get it "right" (call the base class version) or" wrong" separately you have four binary combinations - of which one is "right" and three "wrong". In the early days (pre-standard), cfront got it "wrong" one way, gcc another way, and three commercial compilers for PCs the third way. (So the standard would have imposed equal pain by prescribing the "right" way, leaving them all "broken".) But the first ANSII standard explicitly left it undefined, while the second one not only affirmed that but explicitly warned against calling virtual functions from constructors and destructors.

    (I did bring this up with the committee both times, but was unable to sway them, even to make it a recommendation or to provide a "pedantic construction/destruction order" switch.)

    Getting it "right" would have had considerable benefits. There's a lot of useful things (which I won't go into here) that become easy if it's "right" and breaks badly - or requires combersome workarounds - if it's "wrong". And getting it "wrong" also leads to subtle bugs and interactions even if you're NOT trying to do something fancy.

    (Because it was "wrong" in all the compilers and not forced by the standard, a large programming project I was working on back then was forced into workarounds that gutted the opportunities to build complex objects using member objects, replacing them with smalltalk-style heap-allocated objects strung together by pointers (with enormous overhead as a reault) and creating an initialization function hierarchy parallel to the construction hierarchy to get things properly spun up.

    In the kernel the code must be solid and really should be tight and do things the obvious and simple way. So a feature-gutting, bug-attracting, spec ambiguity like this is a nightmare.

    Thus for me:

    * (d) There's a big fat hole in the standard.

    Is a killer.
  • by Ungrounded Lightning ( 62228 ) on Wednesday October 27, 2004 @07:30PM (#10648327) Journal
    Everywhere else C++ uses extreme care to get the "right" level of virtual function.

    (Or overridden functions in general, whether virtual or not.)
  • Re:C++? (Score:3, Interesting)

    by arkanes ( 521690 ) <arkanes@NoSPam.gmail.com> on Wednesday October 27, 2004 @07:34PM (#10648381) Homepage
    COM is a documented standard and as object models go it's not bad. Better than CORBA, anyway.
  • by Anonymous Coward on Wednesday October 27, 2004 @07:49PM (#10648488)
    Decisions like this (C++ in the Linux kernel) are indicitive of the courses currently running in Computer Science departments world wide.

    Whilst at university I kept up with the compsci courses as well as those required for my physics degree and I have to say I was shocked. There was no C taught at all, and only one course on ASM - a basic first year introductory module which was very leaniently marked. All other "programming" classes were conducted in Java or html (funny given html is a markup language). There was an optional "AI" course which taught a little prolog, but less than could be covered by an average hobbist in 3 nights.

    The java aplications developed were - all in all - no better than what I would expect a decent highschool computer scientist to turn out - simple storage/record keeping apps. The first lesson the freshmen compscis had was how to turn a computer on. "This is the 'power button'". Three students had not used a computer before.

    It was a real eye opener, of the ~100 students enrolled I would have considered employing less 6 of them for a computer related role. There were only 2 I would have employed as programmers, both exception compared with the rest of their cohort.

    I should think that less than half of the graduting class knew what a kernel was let a lone why one shouldn't be written in C++ or Java.

    The Physicists on the other hand became adept at technical multiplatform C programming and were required to take an ASM course which covered the computer science material in a 3 hour afternoon session along with debugging of a 6 A4 page ASM print out for a chip we knew virtually nothing about. ~70% knew at least some unix and virtually all were better programmers than their comparable computer scientist friends, example programs written included a ray tracing app, a graphical simulation package for complex elecomagnetic fields, and galaxy formation simulations.

    The trend continues into postgrad life where one of the barely employable compscis is working towards a PhD in network traffic analysis, despite at our last interaction him not knowing anything about data networking, other than you push the cable with the funny shaped plug on the end into the wall and it goes to the hub.

  • by Baldrson ( 78598 ) on Wednesday October 27, 2004 @07:54PM (#10648538) Homepage Journal
    If you want to optimize exception handling then choose an exception-based execution model. Most people -- particularly Perl programmers -- are familiar with the short-circuit "or" and short-circuit "and" style of programming. "and" binds more tightly than "or" so that a sequence of "and" looks like a normal execution thread with no exceptions, whereas a sequence of "or" looks like a cascade of exception handlers (if all the prior expressions in the "or" sequence fail then you take the next one as an exception handler).

    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

  • by mikefe ( 98074 ) <(mfedyk) (at) (mikefedyk.com)> on Wednesday October 27, 2004 @07:55PM (#10648543) Homepage
    The fact is that the Linux kernel is not just C, it also has parts where it uses assembler because they don't trust even the C compiler for that part of the code.

    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, when you see people benchmarking how many cycles a processor actually takes to perform a snip of code and analyzing the assembly of the C program, I sincerely doubt that they would not be able to do the same for C++.
  • by Peaker ( 72084 ) <gnupeaker@nOSPAM.yahoo.com> on Wednesday October 27, 2004 @07:59PM (#10648577) Homepage
    Shapiro is the guy working on a research Operating System project (The EROS [eros-os.org] system).

    EROS was originally implemented in C++, but then
    it was reimplemented in C [iu.edu].
  • Approach -- and meet (Score:3, Interesting)

    by devphil ( 51341 ) on Wednesday October 27, 2004 @08:19PM (#10648736) Homepage


    Even g++ can give the zero-overhead ideal for exceptions. It's heavily dependant on the platform and the platform-specific ABI.

    Linux on x86 ain't one of those platforms.

  • by jedimark ( 794802 ) on Wednesday October 27, 2004 @08:57PM (#10648993) Homepage
    Sure you can - if you like doing all the dirty work yourself... (not that anythings wrong with dirty work :-)

    Although sometimes it is good to throw in a little abstraction. Being able to visualise some things on a different level really does help a programmer wrap their head around difficult issues that can't easily be solved going the hard yards..

    For example, learning forth as a kid did wonders for me being able to get a very solid grasp on recursion. True, it's not something you use everyday, but it's a different way to think, and some problems can only be solved (efficiently) that way.

    (My point is...) Having a few different programming models at your disposal is not such a bad thing. Yes, along with C++ comes a little bloat, but it also includes C in the bargain. It'd be nice having a little choice for those who want it.

    My language of choice these days is a hybrid of C and C++ (well, more lazy C++) - sure it means I have to link in an extra library, but I can break out with a different model when I see a real need for it.

    It is a little different at the kernel level, but their really isn't much stopping that extra bloat being included when a module is loaded.

  • Re:Alright!! (Score:2, Interesting)

    by argent ( 18001 ) <peter@slashdot . ... t a r o nga.com> on Wednesday October 27, 2004 @09:34PM (#10649223) Homepage Journal
    C++ allows for much better code

    Maybe, it simplifies the work of building an OO design, but C++ also allows Heaven and Hell and all the worlds between. Good native C OO code can be just as good as C++, but I find it hard to believe that anyone could have constructed the Escher cathedral that is Mozilla with mere C.

    I might also protest about the purity of Linux' precious bodily fluids. But when people have embedded Perl in the Linux kernel (or did I hallucinate that one?) and a C compiler in the bootloader, any such declaration must of necessity be accompanied by hoots of hysterical laughter from all right minded slashdotters.
  • Re:Who cares? (Score:1, Interesting)

    by Anonymous Coward on Wednesday October 27, 2004 @09:42PM (#10649274)
    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.

    Most of the Windows kernel is written in C++, too, right?

    Why [are exceptions broken]?

    Exceptions break out of the current function and clean up automatic variables. That's all they do until they're caught. All the hard work is making sure that data consistancy is maintained throughout all your objects during exceptions. It's just as simple to have one part of your function do cleanup and put goto statements to that part instead of bothering with exceptions. I imagine Linus says they're broken because they don't provide any additional benefit over the goto approach, but can be mistaken for providing data consistancy.

    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++?

    The problem is the extra data checking and other things that C++ adds on. For instance, the copy constructor is not optimized (at least in g++), and for instance if you are returning an instance of a class from the function, the copy constructor is called at least three(!) times to return the value. Once to copy whatever return value is created into the local variable at the end of the "return" statement, once to copy that variable into a temporary stack variable in the calling function, and then again to copy that stack variable to the lvalue of the function call. That's standard C++, and there are a few optimizations that can be used, but in general you end up doing a lot of extra work for no reason. You can't optimize those extra copies out because it's an undecidable problem to check whether or not side effects of directly copying to the original function's lvalue will cause race conditions or undefined behaviour, so all three copies are done. Obviously, for performance, the solution is to pass a reference to your local variable into the function so that only a single copy constructor (or other operator) is called, but that's *exactly* what you'd do in straight C. What's the advantage again?

    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.

    So that you have to write *(( datatype *)((int unsigned)&voidpointer+voidoffset))=(datatype)value ; and other nonsense when doing memory management?
  • Re:Question (Score:3, Interesting)

    by multipartmixed ( 163409 ) * on Wednesday October 27, 2004 @10:01PM (#10649409) Homepage
    Different strokes for different folks.

    You're a CS student in college, you don't really need to know. What you need to spend all your time doing is learning how to PROGRAM and do it well.

    Worry about the specific tools later. You could do just as well with just about any language of the right paradigm. C++ is actually a mixed-paradigm language, not all that great for teaching.
  • Re:Alright!! (Score:2, Interesting)

    by yanestra ( 526590 ) on Wednesday October 27, 2004 @10:14PM (#10649474) Journal
    Why ever not? C++ allows for much better code, you just need a compiler that's up to the task, and runtime ABI that is predictable. Granted, standard C++ may not be appropriate, but with some features disallowed, it is ideal (better than C).
    Because C++ makes your program less deterministic.
    By looking at a piece of code, you can't say what happens where if you use C++.
    During every single instruction, an (unexpected?) exception might take place, and every single instruction might be changed from what the author has intended (and tested) when somebody changed the definitions of what those methods were inherited from.
  • by Anonymous Coward on Wednesday October 27, 2004 @10:16PM (#10649487)
    The parent poster has the right idea when he said "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."

    In theory, an exception is just a more expedient return statement -- it lets you immediately branch to the handler. In some sense, they're a bit like using setjmp/longjmp, labeled branches (a feature not found in C/C++), or continuations (another feature not found in C/C++). But it also means that there is absolutely no benefit provided if you only use it as an alternate means of returning to the caller.

    Exception handler addresses can be pushed onto the processor stack just like the return instruction pointer (or they can be pushed onto a separate exception stack). Any function that needs to do exception 'cleanup work' can push its own exception address instead of its caller's.
    a() catches
    b() ^
    c() |
    d() |
    e() throws
    If you're passing an exception through multiple functions, raising an exception can bypass significant number of comparisons and jumps. It also reduces clutter in the intermediate functions that don't have to bother testing for an error condition and passing back a return value.

    However, in C++ you run into the situation where 1) nearly EVERY function has an implicit exception handler to calls all the destructors for the stack variables, and 2) optional exception handlers require expensive runtime typechecking comparisons to see which handler gets to run. The former means you don't end up saving much with C++ catch-all exceptions (i.e. "(...)"), and the latter means you actually end up losing performance with type-specific exception handlers! The article mentions using pointer comparisons here to help reduce this performance hit.

    Basically you use C++ exceptions for convenience/safety, not performance. They're particularly useful when you're calling 'unknown' code like virtual functions/function pointers (in other words: drivers), and that's why there's interest in using them in the kernel.
  • kinda useless... (Score:4, Interesting)

    by Ayanami Rei ( 621112 ) * <rayanami&gmail,com> on Wednesday October 27, 2004 @10:17PM (#10649497) Journal
    Having a linux kernel running as a layer on top of a JVM is kinda useless since it's designed to run some sort of native binaries. So the question becomes: which target architecture do you then emulate in the JVM to accomodate the user space programs, or do you force all userland apps to be java bytecode as well? Then what's the point? Just use straight java on the JVM.

    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:Who cares? (Score:3, Interesting)

    by Pseudonym ( 62607 ) on Wednesday October 27, 2004 @10:55PM (#10649702)

    Precisely, which is my main point: Writing the Linux kernel in C++ is a waste of time because right now, it's already written. Given that nobody wants to waste their time on this, we will never know if Linux is better written in C or C++.

    I can only speak from the point of view of maintainability and readability, but you make a good point that if Linus et al can't read C++, then even this isn't necessarily an advantage.

    It is truly ugly to have multiple acceptable coding paradigms in a large project [...]

    Actually, most large software projects are multi-paradigm. This is because most large software projects have a "soft layer" DSL/scripting component (e.g. Emacs lisp). An OS kernel is a bit special in this regard, in that most of it is low-level stuff held together with internal APIs. The "soft layer" of Linux is user space.

  • Re:kinda useless... (Score:1, Interesting)

    by Anonymous Coward on Wednesday October 27, 2004 @11:06PM (#10649783)
    Better yet, the kernel is the VM; which is the hardware abstraction layer, micro JIT loader, and the virtulization logic for all system processes, with the common java api's layerd on top. That way the 'operating system' proper would be extensible and the Java language self hosting after the first generation due to the native boot level JIT translator. The bootstrap coding and HAL needs to be a JIT binary cache of the first run but the rest of the OS could be assembled on the fly. Truely write once run anywhere once the OS abstraction objects are cached during the first run through the interpreter. Classes could be loaded like drivers to extend the OS or user environment as needed.
  • Re:Alright!! (Score:2, Interesting)

    by orst_sw_engr ( 813827 ) on Thursday October 28, 2004 @01:27AM (#10650684)
    Have you ever debugged at the kernel (protected) level?

    C++ is best avoided at the kernel because of implicate nature of the language. Bugs are harder to find in C++. When an exception occurs, the whole machine must rebooted.

    If you want try this for yourself, just take any amount of code you are working with and every time an exception occurs restart your computer and wait. See how much work you get done.

    Also, while at the kernel mode you must be aware of the whole machine's state including IRQ level, virtual memory, entry context, what IRQs can preempt, and a slough of other details. In user mode you can rely of the state of the machine being fairly stable. However, I would agree that large multi-tiered have many network states that make user mode programming complicated. I have worked in these environments as well.

    Further, you still can write object-orientated code in C if necessary. It just requires the C programmer to manually manipulate the v-table which they create themselves. I have done this. You can do it in ASM too with structs of jump tables.

    Someday C++ will make it into kernel programming, but I think it would be start in a micro-kernel, which is easier to debug.

  • by Lord of the Fries ( 132154 ) on Thursday October 28, 2004 @01:35AM (#10650732) Homepage
    This is very interesting to me. I'm reading this as a novice kernel programmer, but an adept application level programmer with a variety of OO languages used (Smalltalk, C++, OCAML, Objective-C, CLOS). I have to say... C++ is by far the worst realization of the ideals behind OO that I am aware of. That's beside the point though, what I guess I find interesting, is why didn't Apple choose to inject some Objective-C into the kernel (a much better C-OO hybrid). I was not aware they used C++ in the kernel before your post.
  • Re:Alright!! (Score:4, Interesting)

    by Bloater ( 12932 ) on Thursday October 28, 2004 @03:20AM (#10651135) Homepage Journal
    Yes, I have debugged at the kernel level, written a boot loader, switched to protected mode inluding operating the GDT, IDT, page tables, vga registers. written a VGA terminal, etc... I am familiar with x86 assembler, C and C++.

    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.
  • by Old Wolf ( 56093 ) on Thursday October 28, 2004 @03:59AM (#10651284)
    Firstly let me say that I'm not a kernel programmer, and I respect the fact that you have decided against using exceptions. However I'd like to attack your arguments anyway, based on my (limited) point of view, so if you could correct me then that would be good.

    The article said that they had modified exception handling to make it efficient time-wise, so the complaint that it's slower than using error returns no longer applies. (Recall that exceptions only should be thrown in exceptional circumstances, not as an expected part of processing; and exceptional circumstances will usually include some handling such as printk() which they noted takes an order of magnitude more time to run than the process of propagating an exception).

    So let's return to your main point: the risk of an uncaught exception causing a kernel panic is too high.
    (BTW how is this different to the risk of a divide by zero causing a kernel panic in C ? )

    I'd like to make a 'case study': accessing the elements of a std::vector. If you're unfamiliar, then writing:
    v[n]
    is equivalent to using that syntax on an array of ints. However, writing:
    v.at(n)
    is equivalent to writing in C:
    if (n > v_size)
    return some_error_code;
    v[n]
    and then having handling in the caller function for the possibility of that error. Much more concise, don't you think? Especially if you have
    several of these accesses in one expression.

    (Presumably the 'n' would come from some external source that is expected to be in bounds but occasionally may not be. )

    So you have reduced code complexity by not having to do a manual bounds check everywhere. You have no added runtime overhead in the case of the value being in range.
    Also, the case of the uncaught exception is just as bad as the case of an out-of-range array access -- maybe even worse, as it will take longer to find the bug.
    And perhaps the most important: you have the flexibility of being able to put the error handling code at a higher level than just the parent function. In the cause of the completely uncaught exception, at least you have the exception error message to indicate exactly what went wrong. If the kernel crashes from an out-of-range array access you may have no idea what went wrong, especially if it is in a tricky bit to use a debugger.

  • Re:Alright!! (Score:5, Interesting)

    by Bloater ( 12932 ) on Thursday October 28, 2004 @04:12AM (#10651322) Homepage Journal
    Macros are not always easily debugged, identifiers can be replaced wholesale by #defining it, but not *before* the define, so the header that defines a static variable parses fine, then you include a header from another part of the kernel, then you use the identifer. In the next version of the kernel somebody #defines the identifier you are using within the second header.

    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:nice (Score:4, Interesting)

    by Scherf ( 609224 ) on Thursday October 28, 2004 @05:13AM (#10651539)
    Probably because a C++ interface is a pain to access from any other language than C++. Or perhaps because the Win32 API is a C library and cluttering it by adding C++ interface would be much more screwy.

    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"...
  • by drawfour ( 791912 ) on Thursday October 28, 2004 @05:28AM (#10651575)
    That's what pointers are for. Instead of:
    FILE *fp = fopen("foo.txt");

    why not use something like a return code for errors and out parameters of the functions. No globals, no worries about catching exceptions, you just return an HRESULT.

    HRESULT hr = S_OK;
    FILE *fp = NULL;
    hr = FileOpen("foo.txt", &fp);
    if (FAILED(hr)) ...

    This is NOT that hard. Plus HRESULTs can be easily propagated down, and ANYONE can act on a failure if he desires with or without knowing what the failure is.

    If you use exception handling the way it's supposed to be, you catch OBJECTS and not the wonderful catch-all of "...". The problem with using the catch-all of "..." is that truly BAD events like stack overflows are caught. And if you do not know how to recover from a stack overflow, you better abort the program immediately.

    But if you DON'T use the "..." form, and you don't know of ALL types of exceptions that can be thrown... well, one will slip by you and a regular "exception" will just kill your process since it's not handled. I MUCH prefer HRESULTs to handle known and unknown errors. Let a truly bad exception kill my program, and let me handle return codes.
  • Re:Alright!! (Score:2, Interesting)

    by orst_sw_engr ( 813827 ) on Thursday October 28, 2004 @05:34AM (#10651590)
    Well I made two posts and I appreciate your well-written, civil replies. Sorry for using the word naive.

    True, looking at your original post I am not sure where memory management came into play so I will not harp on it too much. I will point out that the pager works at a low interrupt (which makes sense because disk i/o is required and if it was higher it could preempt threads that don't expect memory moved on them). If a higher interrupt is being serviced it will not have access to virtual memory. Memory simply cannot be created at this level. You are right about the guarantee - for exceptions, the stack is easiest to use. You also right about throwing a primitive in C++ -- it uses no memory.

    I agree that SEH (Structured Exception Handling) has its place in the kernel. As a matter of fact, NT has always had this built into its C compiler. (I actually already made reference to this in a post below.) It even has a finally block for cleanup like you are describing (kind of like a destructor). I have found this feature indispensable. So we both agree this is a good feature.

    BUT! I take issue with most other C++ features which I *love* in user mode, but would be a pain to debug in kernel mode. Interestingly I have done some from polymorphism in the kernel by building my own objects with a variant function table. I find this easier to debug while working in the kernel, but in user mode I would never dream of wasting my time doing this myself.

    As far as defines... I guess I have gotten so use to them; they don't bother me. I can track down the symbol.

    When it comes to C++ for me, it is not the system itself. It is the time it takes to debug it. User mode has much better tools for debug C++. Maybe that is the problem.

    You can have the last word. I am done with this subject.

    Oh, I would like to add one thing the system wide catch on NT is the BSOD.

  • by Anonymous Coward on Thursday October 28, 2004 @06:34AM (#10651759)
    I really hope this gets somewhat modded up.

    There IS an OS kernel that is written in pure java - and it actually makes sense!
    It is developed at my university in Erlangen/Germany and called JX.

    http://jxos.org/

    At first I also thought "Bah, screw it". But more interesting is the DESIGN and the on-the-fly merging of domains, which I consider the most interesting _concept_ ever!

    Please see their website for actual implementation designs and benchmarks.
  • Re:Alright!! (Score:2, Interesting)

    by a_hofmann ( 253827 ) on Thursday October 28, 2004 @07:16AM (#10651865) Homepage
    You are absolutely correct that the main problems with compiled C++ lie in the current implementations. But this is a pretty theoretical thing to say, as I don't see this getting much better in near future. C++ compilers have only recently reached a level of full standard compliance, and optimization is surely not yet on par with the things possible for C compilers. C++ is a more complicated language which means it is more difficult to optimize for the compiler, and it is probably not ever possible to optimize to a level that can be reached for C or simpler languages.

    As an example, Windows has a modified microkernel architecture and is a (non-pure) object oriented operating system, so by design it would be logical to implement this in an object oriented language. Still it is no coincidence that most parts of it are written in assembler and C - you just cannot afford to waste percentages of performance for critical kernel sections because of the choice of language, which is not avoidable either, no matter how well you use C++ or optimize with the compiler. And unfortunately most kernel sections are pretty performance critical...

    Btw note that I talk about problems occuring when using the full range of C++ features that make it the beautiful language it is... I ofter hear people talking about C++ matching C performance, but when you look under the hood they are basically using C with some syntactic sugar. This is not of much use, as such designs can be (and are) mostly implemented in C in the same fashion either, as e.g. the object orientism of the Windows kernel I spoke of.
  • Re:nice (Score:3, Interesting)

    by Corngood ( 736783 ) on Thursday October 28, 2004 @10:11AM (#10653028)
    Actually GDI+ has an extremely clean C++ interface. I was actually shocked when I saw it:

    http://msdn.microsoft.com/library/default.asp?url= /library/en-us/gdicpp/GDIPlus/GDIPlusreference.asp ?frame=true [microsoft.com]
  • Re:More Confusion (Score:3, Interesting)

    by joggle ( 594025 ) on Thursday October 28, 2004 @12:00PM (#10654448) Homepage Journal
    consts are especially helpful in reading complex C++ code (so long as there are no const_cast functions or too many mutable variables). It is a nice way of telling whether a parameter is strictly an 'in' or an 'inout/out' using CORBA parlance. Nearly all of the code I've ever seen has far too few comments so syntatic sugar like this can greatly speed up comprehension of what the code is doing. It also makes it easier to port the code (well, interface anyway) to more strictly defined languages (like CORBA IDL). How can it possibly obfuscate the code? (with the premise that const_cast and mutable variables aren't used in abundance, which is bad programming practice anyway)

    It can be a pain in the ass to consistently use consts (because member functions called on const parameters must be const functions which in turn must only call const member functions) but I've never heard any complaints about reading the code.

  • by l4m3z0r ( 799504 ) <kevinNO@SPAMuberstyle.net> on Thursday October 28, 2004 @04:25PM (#10657266)
    Whats wrong with objective-c. I would consider that to be a much more viable option for adding object support into the linux kernel because thats basically what we are talking about. Without objects C++ offers no real benefit over C and in fact with the absence of objects is a detrement. Objective-C on the other hand is pure C with some nifty object support stapled on. Way better and in my opinion much more likely to be accepted by them kernel folks.
  • Re:nice (Score:4, Interesting)

    by myg ( 705374 ) on Friday October 29, 2004 @01:52AM (#10660785)
    Because in the late 80's and early 90's (when NT was written) C++ was quite new and the toolchains didn't have stable ABI's (not that we have a stable ABI today). So things like virtual function tables and such had no standard.

    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.

You knew the job was dangerous when you took it, Fred. -- Superchicken

Working...