Not the author, but the thing that got me interested in the project was some posts the author made on OSDev[0] about trying to minimize the amount of interdependencies in the libc code. A lot of the kernel is written in C++[1] which is a little rare (Haiku, and what else?). They also have a cleaned up zlib that I have used and think is quite nice[2]. Also I almost forgot about os-test[3] which tests POSIX compatibility.
Perl6 has Camelia (https://perl6.org/) for much the same reasons. It's everywhere once you start looking for it. I've taught Ving Tsun Gongfu for about 25 years; used to have fancy uniforms, grades and walls covered with certifications; and put a lot of effort into entertaining people and stroking their egos. These days I'll rent whatever shabby room, show up in regular clothes and focus on teaching the real deal; the people who are in it for the right reasons don't care.
Unfortunately I think that this statement has some truth in it: I work in telecoms where we care about realtime: I was used to work in C but my latest project is in C++, I was curious about how C++ and realtime mix: the answer is quite poorly..
It's not that you can't do realtime in C++: it's that you have to fight against lots of C++ developers who want to apply the non-realtime C++ popular idioms.
For example: using interface classes for mocking objects with googletest, the result: virtual methods everywhere..
Well, the newer comment basically amounts to "Real programmers know to use C, so we keep the uncultured plebes out." Which isn't really any argument against using C++, but is rather the kind of attitude that should be expunged from system developers.
There are reasons to avoid using C++:
* The main benefit of C++ is that it has a standard library that's somewhat usable. Except you can't use standard libraries anyways in kernel code.
* Templates, particularly as they intersect with name lookup, are difficult semantics both to the compiler and the user. Until a decade ago, using templates meant more or less playing roulette as to which compilers could handle it correctly.
* RTTI and exceptions are broken features. It has more or less been accepted that these features are optional in C++.
* The famous saying goes "there's a safe subset to C++, but no one agrees what that subset is." That's still more or less true today.
The main advantage of C++ is that it gets you RAII (which makes dealing with errors much easier, since you're less liable to have issues like gotofail), and you can use templates to build safer ADTs. These are strong benefits in that it's a lot harder to make mistakes as a developer, but there is a strong tendency in this corner of systems developer to assume that stupid mistakes are a fault of the programmer and not the language, and so such benefits are considered flaws because it means letting in stupid people.
> but there is a strong tendency in this corner of systems developer to assume that stupid mistakes are a fault of the programmer and not the language, and so such benefits are considered flaws because it means letting in stupid people.
I don't disagree with you, but I think I can steelman Torvalds' position a little bit:
Low-level development is touchy. If you're not extremely careful, you're going to make errors which no language could possibly prevent, which could very well hard-brick some poor schlub's gear. Selecting for people who know the most "be careful" of all the "be careful" languages means selecting for people who are at least somewhat less likely to make errors like those.
> "Real programmers know to use C, so we keep the uncultured plebes out." ... is rather the kind of attitude that should be expunged from system developers.
I have to disagree in this case. I think the rationale here is that a working, productive mastery of C suggests a developer of a certain caliber. For many projects you would be right, it would be good to encourage the more junior developers to join the project. But, for the Linux kernel, for the core of one of the most widely-deployed pieces of software on the planet, the foundation of countless systems, many of which are performing critical functions, I, frankly, think it's good to filter the dev team for properly competent devs at every possible juncture. If rejecting C++ keeps the noobs out, that's a good thing.
> I think the rationale here is that a working, productive mastery of C suggests a developer of a certain caliber.
Possibly, but that's still pretty silly. Like...I am a cautious programmer by nature. I can write C. I understand the language and its semantics at a fairly intuitive level. I am still cognizant that a moment's inattention means that I am going to screw up in ways that I literally can't with a language that has a scope guard (to say nothing of typing that isn't based on how wide the data structure is, that sort of thing). Not using a language more featureful than C--even to the point of literally banning every feature from the language that isn't a nonvirtual dtor--doesn't "keep the noobs out". It does, however, create classes of bugs. If anything, a "noob" is less likely to realize the danger they're in when fearlessly[0] writing code!
Recognition of my own limits is most of why I don't write C, and if I absolutely must interop with C (passing through to Ruby or whatever) I write the thinnest, dumbest layer I can between it and C++. (These days, I'm trying to go towards Rust for these tasks, but I know C++ much better.) C just does not make you the hard man that many C devotees think it does, that's all.
[0] - This is mostly a compliment and only a little tongue-in-cheek. Novices being willing to write code that I have to think about analytically to feel safe when writing it can, in the general case, often work well enough/long enough to get by.
I can agree that C is a poor language (as opposed to "rich"). It's a pretty thin layer over machine code, and its means of abstraction, and means of static checking that these abstractions hold, are very weak. It was designed around 1970 to work on hardware from 1960s.
The problem is that in early 1990s, when Linux started, no viable alternatives existed. Pascal required a standard library; Modula-2 did not, but it was late to the scene. C++ was poorly supported, and even more full of hidden traps than C. Ada was theoretically a good choice, but accessible compilers did not exist.
C had widespread use, 20 years of history, many compilers, including a free (GPL'd) GCC, wide platform support. Because the language is so compact and simple, these compilers were mostly reliable, there are no complex features that are tricky to implement.
Hence the choice.
Now we have a much wider choice, we have Rust, we have ATS-lang, we have good-quality C++ compilers, we have various tools to synthesize verified C code from higher-level code, etc. We can hope than in 10-15 years we could see e.g. a viable OS kernel written in Rust.
Author here. Sortix is Sortix. MINIX is MINIX. I think each project has different goals and that's fair.
Some thoughts though, for my os-test project I went and installed every free software Unix-like OS and ran a lot of tests on each of them and got experience with each of them.
I don't really consider MINIX a relevant OS. It doesn't have a 64-bit port. The site doesn't offer HTTPS and only has MD5 checksums, so there clearly isn't an attention to security. Sortix offers HTTPS downloads with SHA256 checksums and is up front about its lack of security (next release will do release signing). The latest MINIX release is from 2014, which is a bad project health sign. My latest release is from 2016 (been a bit busy since I got a full time job, but the next release is still being made if at a slower pace, and nightly builds are available and supported). The stable Minix 3.3.0 was pretty buggy and things got better after I upgraded to the Minix 3.4.0 prerelease. The os-test data revealed a bit of a lack of attention to detail in the UDP stack.
I don't think MINIX is really trying to be a more generally used system. It used to be more of an education system, which lead to Linux. I have no plans to make Sortix widely used either, but I avoid making mistakes that prevent adoption as part of the general good work. I want to make a good OS that I personally like.
I'm happy to be compared to systems like MINIX, Haiku and GNU/Hurd. The ideal reaction to someone mentioning Sortix support should be "Eh, Sortix is cool but who cares? I guess I can do it if trivial". And that's fine, at least they heard of it. I'm a one person project with a small community but I think I'm competing reasonably in this space. I don't really consider Minix that usable. GNU/Hurd is alright but the GNU project is notoriously bad at actually releasing an OS themselves with any sort of technical vision and quality. Haiku is pretty interesting, though it seems to be focusing more on being BeOS than being a general purpose system (it doesn't have a multi user support for instance, which Sortix does have, though with a few security vulnerabilities). They're all different projects with different goals and strengths and I try to make Sortix better whenever I can do it.
I want Sortix to have a really good and inclusive community. I enjoy the coding but I really enjoy putting the whole OS together and building a whole project and community.
Author here. POSIX requires errno to be thread local, but with few requirements. Commonly libc's #define errno (*__get_errno_location()). Why? It's because the thread local storage isn't online very early on. The libc literally has to open its own program executable and locate the the thread local storage and mmap a copy of it for each thread. Thread level storage comes online late in Linux, which bloats statically linked executables with code to parse their own executable.
In Sortix, I just have the kernel set up the TLS for statically linked executables and just declare errno as:
__thread int errno;
That means errno is online from the very first instruction in _start in statically linked executables, without the need to parse the program file in early libc. There's no error conditions between _start and main. This is the kind of implementation quality I want to have in Sortix and part of why I develop Sortix.
Author here. Like in Linux, libc provides errno on Sortix. The difference is that glibc does "#define errno (*__get_errno_location())" while Sortix libc does "__thread int errno;". linux syscalls return a negative value containing the negated errno, while Sortix system calls use two output registers: The return value register and the errno register. That allows Sortix system calls to legitimately return -42 if they want, which is not possible on Linux. Sortix libc assigns the errno register to the thread local errno if the errno register is non-zero.
Not the author, but the kernel is Multiboot compliant. See: https://sortix.org/man/man7/installation.7.html 'If you wish to dual boot, you need an existing operating system with a multiboot compliant bootloader such as GRUB.'
The kernel(7) is a multiboot compatible binary that can be loaded by any multiboot specification compatible bootloader such as GRUB. You need to use such a bootloader to boot the operating system. You will be offered the choice of installing GRUB as the bootloader."
Allowing the user to choose their own bootloader makes this particular small project a rare find, IMO.
I use another multiboot specification compatible bootloader that I prefer over grub.
I also like how he offers both 32 and 64bit.
I guess this project has been posted to HN before. Perhaps at that time it still did not yet have networking.
Author here. Yep, I don't want to force a particular bootloader on anyone. The bootloader is a piece of software owned by the system administrator, not necessarily by any of the several operating systems installed side by side. If I force a bootloader on the user, that makes dual boot configuration harder, and it's important to allow that. I happen to follow GRUB's multiboot specification, which has the advantage that a lot of bootloaders implement it. It's not perfect though and I'll probably invent and adopt my own bootloader protocol in the future, but the sysadmin's choice of bootloader continues to be important on my mind.
I've been poking at something similar lately, and if you're mostly running on VMs, I would suggest taking a look at the virtio interfaces. they are high performance, asynch, and relatively easy to implement.
Yep. I already have an issue about virtio filed at <https://gitlab.com/sortix/sortix/issues/473>. Not too high priority to implement but something I'd love to get to. Feel free to post additional hints there if you have additional tips for when I get around to doing it.
I started a note on your gitlab issue, but saw you already had an mmio reference linked. i did the pci version and it looks about the same complexity.
aside from a reference, being able to instrument the device side on qemu makes debugging drivers a total cakewalk. so do that. best of luck with your project. i wish more people went through the exercise. even though a mature OS after decades of maintenance might exceed 1M lines, you really dont need anywhere close to that to get what you need done. you learn alot, and can make your own model
Before I get all negative, I'll say that this looks very good for education[1], but I'm really curious about why the word "modern" was used.
POSIX is ancient, is overspecified in very important areas (which, thankfully, many/most implementations ignore/work around), is underspecified in very important areas, holds us to a C-based API/ABI, doesn't even have sane "atomic" file operation semantics, etc. etc.
POSIX is not something to aspire to, IMO. We tolerate it because we have to, AFAICT.
(Rant over. I can only apologize, I just sometimes get a little angry that we're held back technologically because of this nonsense.)
[1] Even given the limitations, which are very clearly acknowledged. Kudos to the project people for that!
Author here. I'll probably omit the word 'modern' in the next release. Not for the reasons listed here, but because a bunch of stuff purports to be modern while forgetting the lessons of the past.
I implement POSIX not for the sake implementing POSIX, but because it allows me to port a lot of the software that's already written. The core POSIX specification is fairly alright and not that intrusive in my design, the worst parts of POSIX are in optional sections like XSI that I simply omit implementing. I implement a lot of extensions found in Linux and BSD that enhance upon POSIX, while also providing a few of my own. POSIX doesn't say anything about the ABI and doesn't prevent other languages. Atomic file operations are dear to my heart and something I'd like to extend upon in Sortix. Note that POSIX does specify rename(2) is atomic. I implement POSIX when it's convenient and omit doing so when not.
I'm happy to acknowledge the limitations of Sortix up front. It's important to establish this level of honesty early on to set the right expectations and establish trust. I warn up front about the security problems in Sortix (that exist at this time). If you follow the documentation, you should get predictable results with no nasty surprises.
I think Sortix is suitable for education projects. There's some more clean ups that can make it better. But it's of a reasonable size, it doesn't have that many dirty hacks, and it's fairly well organized.
This shows a bit of a misunderstanding about what POSIX is. It isn't about operating systems, it (IEEE 1003.1) is about source-code compatibility for 2 languages: C99, and Shell. POSIX doesn't say anything about an ABI, and there's nothing holding the system as a whole to a C-based API. It's specifying C compatibility, of course it's talking about a C API! If you want a different language API, POSIX (1003.1) isn't relevant to you. Totally non-UNIXy systems like z/OS are POSIX certified, because they have source-code compatibility with C99 and Shell programs written against POSIX; that doesn't mean it is held to a C-based API.
> POSIX doesn't say anything about an ABI, and there's nothing holding the system as a whole to a C-based API. It's specifying C compatibility, of course it's talking about a C API! If you want a different language API, POSIX (1003.1) isn't relevant to you.
(Double-replied because I wanted to separate this bit out.)
Effectively, it seems you're saying: "Ok, you don't want to implement a C API"[1], well, jolly good luck to you, then. The premise of this whole conversation was that POSIX was a dominating force, and now you're saying you don't have to participate...?
[1] A C API, obviously, requires an extreme amount of either 1) being C, or 2) being compatible enough with C that it doesn't matter either way, or 3) giving up entirely on the POSIX ecosystem.
So... how is that not being absurdly badly influenced by POSIX?
37 comments
[ 4.6 ms ] story [ 85.6 ms ] thread[0]https://wiki.osdev.org/User:Sortie/Sortix_Thread_Local_Stora...
[1]https://gitlab.com/sortix/sortix/tree/master/kernel
[2]https://sortix.org/libz/
[3] https://sortix.org/os-test/
http://harmful.cat-v.org/software/c++/linus
I wonder if things have changed in the decade since he penned that.
It's not that you can't do realtime in C++: it's that you have to fight against lots of C++ developers who want to apply the non-realtime C++ popular idioms.
For example: using interface classes for mocking objects with googletest, the result: virtual methods everywhere..
There are reasons to avoid using C++:
* The main benefit of C++ is that it has a standard library that's somewhat usable. Except you can't use standard libraries anyways in kernel code.
* Templates, particularly as they intersect with name lookup, are difficult semantics both to the compiler and the user. Until a decade ago, using templates meant more or less playing roulette as to which compilers could handle it correctly.
* RTTI and exceptions are broken features. It has more or less been accepted that these features are optional in C++.
* The famous saying goes "there's a safe subset to C++, but no one agrees what that subset is." That's still more or less true today.
The main advantage of C++ is that it gets you RAII (which makes dealing with errors much easier, since you're less liable to have issues like gotofail), and you can use templates to build safer ADTs. These are strong benefits in that it's a lot harder to make mistakes as a developer, but there is a strong tendency in this corner of systems developer to assume that stupid mistakes are a fault of the programmer and not the language, and so such benefits are considered flaws because it means letting in stupid people.
I don't disagree with you, but I think I can steelman Torvalds' position a little bit:
Low-level development is touchy. If you're not extremely careful, you're going to make errors which no language could possibly prevent, which could very well hard-brick some poor schlub's gear. Selecting for people who know the most "be careful" of all the "be careful" languages means selecting for people who are at least somewhat less likely to make errors like those.
I have to disagree in this case. I think the rationale here is that a working, productive mastery of C suggests a developer of a certain caliber. For many projects you would be right, it would be good to encourage the more junior developers to join the project. But, for the Linux kernel, for the core of one of the most widely-deployed pieces of software on the planet, the foundation of countless systems, many of which are performing critical functions, I, frankly, think it's good to filter the dev team for properly competent devs at every possible juncture. If rejecting C++ keeps the noobs out, that's a good thing.
Possibly, but that's still pretty silly. Like...I am a cautious programmer by nature. I can write C. I understand the language and its semantics at a fairly intuitive level. I am still cognizant that a moment's inattention means that I am going to screw up in ways that I literally can't with a language that has a scope guard (to say nothing of typing that isn't based on how wide the data structure is, that sort of thing). Not using a language more featureful than C--even to the point of literally banning every feature from the language that isn't a nonvirtual dtor--doesn't "keep the noobs out". It does, however, create classes of bugs. If anything, a "noob" is less likely to realize the danger they're in when fearlessly[0] writing code!
Recognition of my own limits is most of why I don't write C, and if I absolutely must interop with C (passing through to Ruby or whatever) I write the thinnest, dumbest layer I can between it and C++. (These days, I'm trying to go towards Rust for these tasks, but I know C++ much better.) C just does not make you the hard man that many C devotees think it does, that's all.
[0] - This is mostly a compliment and only a little tongue-in-cheek. Novices being willing to write code that I have to think about analytically to feel safe when writing it can, in the general case, often work well enough/long enough to get by.
The problem is that in early 1990s, when Linux started, no viable alternatives existed. Pascal required a standard library; Modula-2 did not, but it was late to the scene. C++ was poorly supported, and even more full of hidden traps than C. Ada was theoretically a good choice, but accessible compilers did not exist.
C had widespread use, 20 years of history, many compilers, including a free (GPL'd) GCC, wide platform support. Because the language is so compact and simple, these compilers were mostly reliable, there are no complex features that are tricky to implement.
Hence the choice.
Now we have a much wider choice, we have Rust, we have ATS-lang, we have good-quality C++ compilers, we have various tools to synthesize verified C code from higher-level code, etc. We can hope than in 10-15 years we could see e.g. a viable OS kernel written in Rust.
Some thoughts though, for my os-test project I went and installed every free software Unix-like OS and ran a lot of tests on each of them and got experience with each of them.
I don't really consider MINIX a relevant OS. It doesn't have a 64-bit port. The site doesn't offer HTTPS and only has MD5 checksums, so there clearly isn't an attention to security. Sortix offers HTTPS downloads with SHA256 checksums and is up front about its lack of security (next release will do release signing). The latest MINIX release is from 2014, which is a bad project health sign. My latest release is from 2016 (been a bit busy since I got a full time job, but the next release is still being made if at a slower pace, and nightly builds are available and supported). The stable Minix 3.3.0 was pretty buggy and things got better after I upgraded to the Minix 3.4.0 prerelease. The os-test data revealed a bit of a lack of attention to detail in the UDP stack.
I don't think MINIX is really trying to be a more generally used system. It used to be more of an education system, which lead to Linux. I have no plans to make Sortix widely used either, but I avoid making mistakes that prevent adoption as part of the general good work. I want to make a good OS that I personally like.
I'm happy to be compared to systems like MINIX, Haiku and GNU/Hurd. The ideal reaction to someone mentioning Sortix support should be "Eh, Sortix is cool but who cares? I guess I can do it if trivial". And that's fine, at least they heard of it. I'm a one person project with a small community but I think I'm competing reasonably in this space. I don't really consider Minix that usable. GNU/Hurd is alright but the GNU project is notoriously bad at actually releasing an OS themselves with any sort of technical vision and quality. Haiku is pretty interesting, though it seems to be focusing more on being BeOS than being a general purpose system (it doesn't have a multi user support for instance, which Sortix does have, though with a few security vulnerabilities). They're all different projects with different goals and strengths and I try to make Sortix better whenever I can do it.
I want Sortix to have a really good and inclusive community. I enjoy the coding but I really enjoy putting the whole OS together and building a whole project and community.
In Sortix, I just have the kernel set up the TLS for statically linked executables and just declare errno as:
__thread int errno;
That means errno is online from the very first instruction in _start in statically linked executables, without the need to parse the program file in early libc. There's no error conditions between _start and main. This is the kind of implementation quality I want to have in Sortix and part of why I develop Sortix.
What does Sortix offer that is lacking in Xv6?
https://pdos.csail.mit.edu/6.828/2014/xv6.html
[1] http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ed...
If not, is it possible to use syslinux or another bootloader instead of grub?
"Bootloader
The kernel(7) is a multiboot compatible binary that can be loaded by any multiboot specification compatible bootloader such as GRUB. You need to use such a bootloader to boot the operating system. You will be offered the choice of installing GRUB as the bootloader."
Allowing the user to choose their own bootloader makes this particular small project a rare find, IMO.
I use another multiboot specification compatible bootloader that I prefer over grub.
I also like how he offers both 32 and 64bit.
I guess this project has been posted to HN before. Perhaps at that time it still did not yet have networking.
aside from a reference, being able to instrument the device side on qemu makes debugging drivers a total cakewalk. so do that. best of luck with your project. i wish more people went through the exercise. even though a mature OS after decades of maintenance might exceed 1M lines, you really dont need anywhere close to that to get what you need done. you learn alot, and can make your own model
Before I get all negative, I'll say that this looks very good for education[1], but I'm really curious about why the word "modern" was used.
POSIX is ancient, is overspecified in very important areas (which, thankfully, many/most implementations ignore/work around), is underspecified in very important areas, holds us to a C-based API/ABI, doesn't even have sane "atomic" file operation semantics, etc. etc.
POSIX is not something to aspire to, IMO. We tolerate it because we have to, AFAICT.
(Rant over. I can only apologize, I just sometimes get a little angry that we're held back technologically because of this nonsense.)
[1] Even given the limitations, which are very clearly acknowledged. Kudos to the project people for that!
I implement POSIX not for the sake implementing POSIX, but because it allows me to port a lot of the software that's already written. The core POSIX specification is fairly alright and not that intrusive in my design, the worst parts of POSIX are in optional sections like XSI that I simply omit implementing. I implement a lot of extensions found in Linux and BSD that enhance upon POSIX, while also providing a few of my own. POSIX doesn't say anything about the ABI and doesn't prevent other languages. Atomic file operations are dear to my heart and something I'd like to extend upon in Sortix. Note that POSIX does specify rename(2) is atomic. I implement POSIX when it's convenient and omit doing so when not.
I'm happy to acknowledge the limitations of Sortix up front. It's important to establish this level of honesty early on to set the right expectations and establish trust. I warn up front about the security problems in Sortix (that exist at this time). If you follow the documentation, you should get predictable results with no nasty surprises.
I think Sortix is suitable for education projects. There's some more clean ups that can make it better. But it's of a reasonable size, it doesn't have that many dirty hacks, and it's fairly well organized.
This shows a bit of a misunderstanding about what POSIX is. It isn't about operating systems, it (IEEE 1003.1) is about source-code compatibility for 2 languages: C99, and Shell. POSIX doesn't say anything about an ABI, and there's nothing holding the system as a whole to a C-based API. It's specifying C compatibility, of course it's talking about a C API! If you want a different language API, POSIX (1003.1) isn't relevant to you. Totally non-UNIXy systems like z/OS are POSIX certified, because they have source-code compatibility with C99 and Shell programs written against POSIX; that doesn't mean it is held to a C-based API.
Do we still have any quarrel over wording?
(Double-replied because I wanted to separate this bit out.)
Effectively, it seems you're saying: "Ok, you don't want to implement a C API"[1], well, jolly good luck to you, then. The premise of this whole conversation was that POSIX was a dominating force, and now you're saying you don't have to participate...?
[1] A C API, obviously, requires an extreme amount of either 1) being C, or 2) being compatible enough with C that it doesn't matter either way, or 3) giving up entirely on the POSIX ecosystem. So... how is that not being absurdly badly influenced by POSIX?