Exactly. You shouldn't concentrate on the performance of the component that is rarely run. You need to measure the whole impact of using exceptions, and one of those impacts is in the common case, you get to run whole swathes of code without having to check (and branch) for errors. Fewer pipeline hazards, fewer instructions to execute. It may be a marginal instantaneous performance improvement, but the cumulative effect may well negate any performance impact of an expensive exception unwind mechanism.nullplan wrote:Yes. I can't find the stats right now, but if the exception triggers, the latency is orders of magnitude above the other error handling methods. The "zero cost" exception handling model is especially bad about this, since in that case once the exception starts you have to start reading tables. And reading DWARF2 debug information in order to unwind the stack. Error code handling is way better optimized. And the costs of error codes vs. "zero cost" if no exception happens doesn't appear to be all that bad. Not orders of magnitude, certainly.thewrongchristian wrote:Do they have terrible performance, though?
However, it usually doesn't matter because exceptions should be rare.
Clarification of C++ kernel development issues
-
- Member
- Posts: 426
- Joined: Tue Apr 03, 2018 2:44 am
Re: Clarification of C++ kernel development issues
- AndrewAPrice
- Member
- Posts: 2300
- Joined: Mon Jun 05, 2006 11:00 pm
- Location: USA (and Australia)
Re: Clarification of C++ kernel development issues
I kept things simple by going just C in the kernel (with no standard library), and trying to get full C++ support in userland.
I found with C++, too many of the cool features I want to use (like lambdas) required a C standard library. I ended up porting libc++ and it has finally paid off (yay, I can use lambdas, std::map, std::string_view, std::thread, std:unique_ptr, etc. now!) It was a lot of work, and the biggest part of it was that every C++ standard library I looked into porting required a C standard library.
Now, porting a C standard library was a lot of work. After investigating many different libraries for completeness (e.g. many of the smaller hobby libraries are missing math functions, or they just implemented the pure C Standard Library and the C++ standard libaries would try to depend on pthreads) I settled on Musl.
Despite my OS not being Unix-like, I found it super easy to port because all the interaction with the underlying OS goes through a set of __syscall functions, so I built a giant switch statement over the syscall number then I stubbed out each of the system calls to print "System call <name> is unimplemented" and implemented as needed.
For example, when I went to use std::thread, I saw "System call set_tid_address is unimplemented" so I had to figure out what that syscall does and how to implement similar behavior either in my microkernel or emulate it in my library.
The good news is that it didn't take many syscalls to implement (I think mmap, munmap, writev is enough to get you started), and my mmap implementation is very basic - I print out warnings if I try to use an unimplemented feature.
I know you were asking about C++ in the kernel. Getting basic C++ language features (templates, classes, virtual methods, etc.) is straight forward enough and is outlined on the Wiki. Getting the full C++ language is a lot of work, because it requires a C and C++ standard library. It was a pain in userland. I wouldn't want to try it in kernelland.
A microkernel makes things easier in this regard. I can keep the kernel small and written in C with no standard library, then drivers, services, and user applications run in userland and can use the full C++ language.
I found with C++, too many of the cool features I want to use (like lambdas) required a C standard library. I ended up porting libc++ and it has finally paid off (yay, I can use lambdas, std::map, std::string_view, std::thread, std:unique_ptr, etc. now!) It was a lot of work, and the biggest part of it was that every C++ standard library I looked into porting required a C standard library.
Now, porting a C standard library was a lot of work. After investigating many different libraries for completeness (e.g. many of the smaller hobby libraries are missing math functions, or they just implemented the pure C Standard Library and the C++ standard libaries would try to depend on pthreads) I settled on Musl.
Despite my OS not being Unix-like, I found it super easy to port because all the interaction with the underlying OS goes through a set of __syscall functions, so I built a giant switch statement over the syscall number then I stubbed out each of the system calls to print "System call <name> is unimplemented" and implemented as needed.
For example, when I went to use std::thread, I saw "System call set_tid_address is unimplemented" so I had to figure out what that syscall does and how to implement similar behavior either in my microkernel or emulate it in my library.
The good news is that it didn't take many syscalls to implement (I think mmap, munmap, writev is enough to get you started), and my mmap implementation is very basic - I print out warnings if I try to use an unimplemented feature.
I know you were asking about C++ in the kernel. Getting basic C++ language features (templates, classes, virtual methods, etc.) is straight forward enough and is outlined on the Wiki. Getting the full C++ language is a lot of work, because it requires a C and C++ standard library. It was a pain in userland. I wouldn't want to try it in kernelland.
A microkernel makes things easier in this regard. I can keep the kernel small and written in C with no standard library, then drivers, services, and user applications run in userland and can use the full C++ language.
My OS is Perception.
Re: Clarification of C++ kernel development issues
I am glad to hear that porting Musl wasn't too much work. Right now I am happy with newlib inside my kernel, but it is not good enough for userspace. I have been keeping an eye on Musl for a while and I might just go with it instead of the glibc monster.AndrewAPrice wrote:Now, porting a C standard library was a lot of work. After investigating many different libraries for completeness (e.g. many of the smaller hobby libraries are missing math functions, or they just implemented the pure C Standard Library and the C++ standard libaries would try to depend on pthreads) I settled on Musl.
As for C++, I really only found two contenders: libstdc++-v3 that comes with GCC or the stdc++ that comes with Clang. I couldn't find any other up to date implementation. They both rely on having a libc and pthread.
-
- Member
- Posts: 426
- Joined: Tue Apr 03, 2018 2:44 am
Re: Clarification of C++ kernel development issues
I'm a bit surprised that things like exceptions would require anything but libgcc. If exception handling was self contained and provided entirely within libgcc, I'd dump much of my C based kernel and re-implement it in C++. I love the idea of RAII and exceptions to handle the fiddly bits of cleaning up resources, and templates make a whole lot of code easier to reuse. I wouldn't need the entirety of stdc++, I'd just like the exceptions and templates.kzinti wrote: As for C++, I really only found two contenders: libstdc++-v3 that comes with GCC or the stdc++ that comes with Clang. I couldn't find any other up to date implementation. They both rely on having a libc and pthread.
Hmm, a freestanding C++ library for kernel use. Perhaps an idea for a future project.
Re: Clarification of C++ kernel development issues
As I understand it, you do only need libgcc for exceptions (basically the stack unwnding code and the ABI for throwing/catching exceptions is in libgcc).thewrongchristian wrote:I'm a bit surprised that things like exceptions would require anything but libgcc.
But if you want to throw a std::bad_alloc(), then you need a definition for it and that is not in libgcc.
You could just use your own exceptions and ignore the stdc++ library if you wanted to.
-
- Member
- Posts: 426
- Joined: Tue Apr 03, 2018 2:44 am
Re: Clarification of C++ kernel development issues
Ooh. I'm not fussed about std::bad_alloc() or any other std definition. I might look at that over the weekend.kzinti wrote:As I understand it, you do only need libgcc for exceptions (basically the stack unwnding code and the ABI for throwing/catching exceptions is in libgcc).thewrongchristian wrote:I'm a bit surprised that things like exceptions would require anything but libgcc.
But if you want to throw a std::bad_alloc(), then you need a definition for it and that is not in libgcc.
You could just use your own exceptions and ignore the stdc++ library if you wanted to.
I currently define my own exceptions using setjmp/longjmp and some CPP syntactic sugar. It works well enough, but I'd love proper stack unwinding, and adding that to my C exceptions adds runtime overhead whether I throw an exception or not.
Re: Clarification of C++ kernel development issues
The difficult part here is that you will need to have a number of pthread functions implemented for this to work. What's more, you will need to compile libgcc itself with the same phtread definitions you will use in the kernel (i.e. pthread.h).thewrongchristian wrote:I might look at that over the weekend.
This is what I needed to compile libgcc *and* libstdc++. It is possible that you don't need all of it if you only build libgcc.
https://github.com/kiznit/build-gcc-and ... /pthread.h
Now my longer term plan is likely to replace the stack unwinding code in libgcc with something that doesn't require memory allocations and/or a pthread interface. But I am not there yet and want to focus on solving the reentrancy issues with using libstdc++. As far as I can tell this basically means the internal optimized memory allocator and the stack unwinding code.
- AndrewAPrice
- Member
- Posts: 2300
- Joined: Mon Jun 05, 2006 11:00 pm
- Location: USA (and Australia)
Re: Clarification of C++ kernel development issues
libc++ was a breeze to port. I don't remember if I had to change any code other than define some symbols in the build rules. I think it was so easy to port because it doesn't do any raw system calls - its implemented by calling the C standard library and some POSIX functions, which makes C++ easy to port to a system with a C ecosystem.thewrongchristian wrote:Hmm, a freestanding C++ library for kernel use. Perhaps an idea for a future project.
So, if you had a freestanding C library for use in a kernel, I'm confident you could port libc++ to your kernel.
I don't know if there's a market for a C++ standard library that doesn't require a C standard library since it would mean double porting your system calls (unless there is a market for people who want to use pure C++ with no C headers?)
Every so often a proposal is floated here for a public domain libc, and there are pdclib and libc11, but they're all missing a lot of functionality. It would be nice to for us to encourage or contribute to these so we can see a more complete implementation that's super easy to port!
My OS is Perception.
Re: Clarification of C++ kernel development issues
Is a C++ lib without stdclib possible at all? I mean, C++ can use C functionality.
Greetings
Peter
Greetings
Peter
Re: Clarification of C++ kernel development issues
I don't think it would make sense. The C library is a subset of the C++ library. The only part you need for libc++ that is not part of libc is multithreading support, and pthread is available everywhere. So what is done right now makes sense and I wouldn't see the point of trying to do it differently.