For very specialized (probably embedded, but maybe other) use cases, I can see the value of specialized operating system which dispenses with time slice scheduling within a core and just assigns waiting tasks to a free core when/if it becomes available. On systems with very high core counts, and with lots of short lived tasks, there could be some value to this.
Even back then, on many machines and operating systems it's not like the whole world stopped when a process would not give up time slice. Things like mouse cursors, keyboard buffering, and often even some I/O were able to proceed because the hardware assisted in making that possible.
The thing is, I don't think going cooperative simplifies much.. you still have to handle concurrent access to shared resources, and re-entrancy etc. By the time you've made your operating system able to handle that (memory, VM subsystem, I/O, etc.) from multiple cores... you may as well just go implement timeslicing as well.
The opposite could work: OS is cooperative, unless some threshold of resource usage is triggered (a timer interrupt of instance). It then context switch to enter a, hopefully rare, failure mode, thus turning preemptive. Kill the app, and get back into cooperative mode. Let's call it optimistically cooperative & pessimistically preemptive.
That's literally the definition of preemptive scheduling.
Also: this is more like an app itself than an OS, for it to be a proper operating system you'd expect at a minimum memory barriers between applications. In that sense the bar for what an OS is has been raised quite a bit since the times of CP/M where it was more of a 'handy library to do some I/O for me' (on mainframes and mini computers there were already proper operating systems back then but on micro computers we had to wait until OS/9 to have something similar).
What was it called? Do you have more details?
People did not move away from cooperative multitasking for operating systems because it solved every "run-away usage of resource" problem for all time. They did it specifically because, as you note, it makes incredibly simple application-level errors, whether they are design-level (UI thread blocked) or simple errors (accidental infinite loop) totally devastating to the entire state of the system. This is pretty bad whenever your system is designed to run arbitrary computer programs -- but even if it isn't (e.g. fixed taskset in cooperative microcontroller OSs), it's just not robust to any kind of runaway failure, and you need to be very careful to ensure it's reliable.
In the end though, all this really does is perhaps change how aggressive a pre-emptive system needs to be. It could wait longer to pre-empt. Fundamentally though, the design would still need to be pre-emptive.
In practice, I'm not sure how relevant pre-empting is any more. Software is much better behaved than it used to and I rarely see these runaway processes anymore. And when they do it's usually pegging a single core at 100% while other processes share the remaining core.
For the programmer, it's most convenient when the isolation between unrelated programs is maximal but isolation between related programs is minimal; but for the user it's the most convenient when programs are maximally isolated in terms of computation, but not for other things such as storage/permissions etc. Practically, this requires a complex scheduling mechanism that is more preemptive than cooperative, but also cooperative a little. E.g. in linux, it's not particularly hard for a rogue program to bring the system to halt with something like a fork bomb (especially if swap is turned on). Even if you have a preemptive scheduler, if your program has 99% of the threads running in the system, it's effectively cooperative because chances are you're scheduled most of the time anyway.
Certainly not, cooperative multitasking is used all the time in userspace programs to great effect, and OSs can do the same thing if the limitations are understood.
For the OS that's the focus of this post though, I think it does have the aim of being general purpose and running whatever you want on it. At that point the limitations aren't really acceptable (which the author acknowledges), and that's why the whole question of "what happens when a program misbehaves?" has come up. If the answer is "preempt the process to run it later" then it's not actually a cooperative system and application developers need to keep that in mind.
Nope, you are completl right! A while (true) might slow down the system, but even that is not necessarily the case: I wrote a program to test this (based on the pseudocode in the readme) and my system is totally usable, with basically zero lag! This is the power of a well-written operating system that includes a mysterious concept called priorities. There is actually no discernable different when running the program (other than battery use and temperature going up). In fact, I am running that program as I right this because the difference is so negligable.
program: https://paste.sr.ht/~pitust/47dc80ff09243b4bf41a08ae9434a32c...
> In terms of security, this would make denial of service attacks against such systems trivial
Denial of service attacks where you have access to the target system are not super hard to mount AFAIK.
Not because it isn't a resource disaster. But because unless you measure something, you might not notice.
Oh! You did measure something. Battery use and temp. There you go. It's a disaster. Some kind of management of such irresponsible threads is definitely a good idea.
> Oh! You did measure something. Battery use and temp. So I didn't do any scientific measurements, but the temperature difference doesn't seem to be very significant.
> It's a disaster. But cooperative scheduling isn't any better. In fact, it's even worse! Since if an app doesn't yield (and let's face it, no app is perfect), you can easily get a deadlock. Developing for such a system without a VM sounds like a nightmare too to be honest.
> Some kind of management of such irresponsible threads is definitely a good idea. What kind of managment do you propose? I mean, if there is nothing else running on the system, it's probably okay to just let them keep running (it's not like they are harming anything except battery life, and you might want something that can max all cpu cores, like if you are running a compilation or a video game).
> The argument that a cooperative scheduling is doomed to fail is overblown. Apps are already very much cooperative. For proof, run a version of that on your nice preemptive system: [...] Might fill your swap and crash unsaved work on other apps.
The difference is that in a preemptive system, a `while (true)` might slow down the system, but in a cooperative system, the machine effectively halts. Like for good. If you're caught in a loop and don't yield control back, you're done.
In terms of security, this would make denial of service attacks against such systems trivial. You could exploit any bug in any application and it would bubble up to the entire system.
Or maybe I'm all wrong. I'm not an OS dev, so please someone correct me.