C++ In The Linux kernel
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."
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).
Nothing will come out of it, for the simple reason that C++ does not belong in any kernel. In a kernel, all the code needs to be transparent, and you definitely don't want to hide implementation and the usual abstractions.
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.
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.
It's not the slowliness, it's the obscuirty and the lack of control over the binary code size it introduces. Something as simple as 'a == b' may easily add few KB to the kernel.
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.
3.243F6A8885A308D313
Nope. It's a condition that the throwing code couldn't handle. Someone else can handle it.
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.
Care about electronic freedom? Consider donating to the EFF!
Oh dear. Another person who thinks that exceptions should never be thrown.
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.
Linux made his view on C++ in the kernel a while ago here
I'm an embedded developer. I've done some projects as C only and some as C++. With proper discipline C++ can actually generate smaller, more compact code than straight C. But getting the infrastructure done is a bit harder.
.38 special.
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
The core of Windows is written mostly in C. The GDI was written in C++ and the chief Kernel architect of WinNT (David Cutler) continually jabbed the Graphics group on their choice of C++.
I don't suspect you will be finding C++ in NTOSKRNL any time soon. I think Cutler would beat up anybody who tried.
I think that deserved +1 Funny.
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.
Some people say exceptions. I say goto. Easy to understand, easy to implement, and very clean IMO:
/* reuse sin struct from accept() */
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;
}
Your first three are part of OOP [hint: Java has them too]
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).