I am not sure what point you are attempting to make here. As written, it is more or less completely wrong.
NT and Unix kernels both execute threads. Threads can be created in a few microseconds. Processes are heavy weight on both NT and Unix kernels.
The only thing I can think of is the long-standing idea that Unix tends to encourage creating new processes and Windows-related OS kernels tend to encourage creating new threads. This is not false - process creation on Windows-related OS kernels is an extremely heavyweight process, certainly comparing it with any Unix. But it doesn't make the quote from you above correct.
On a separate note, the state of things at the point of creation of NT is really of very little interest other than than to computer historians. It has been more than 30 years, and every still-available Unix and presumably NT have continued to evolve since then. Linux has dozens to hundreds of design features in it that did not exist in any Unix when NT was released (and did not exist in NT either).
It’s not so much “heavyweight” vs “lightweight” but that NT has been by design more limited in how you can create new virtual memory spaces.
For better or worse NT tied the creation of VM spaces to this relatively expensive object to create which has made emulating Unix like behavior historically a pain in the ass.
Anyway, I see your point about the bleed between the different semantics of a task_t in the linux kernel.
Yes, what I was alluding to somewhat cryptically was things like tgids and the related tkill/tgkill syscalls that as far I am aware were added with the implementation of 1:1 pthread support in mind.
It's sad that the article didn't mention VMS or MICA since NT didn't magically appear out of the void two years after Microsoft hired the NT team. MICA was being designed for years at DEC West as part of the PRISM project.
It started elegant, but all the backwards compatibility, technical debt, bad ideas, and dozens of versions later, with an endless list of perpetual features driven by whoever had a bigger wand at Microsoft at the time of their inception, takes a toll. Windows now is much more complicated than it could be.
It shocks me some apps get Windows NT4 style buttons even on Windows 11.
Most definitely. There was a lot of design cleanup from VMS (e.g. fork processes -> DPCs, removing global PTEs and balance slots, etc), optimizations (converging VMS's parallel array structure of the PFN database into one), and simplification (NT's Io subsystem with the "bring your own thread" model, removing P1 space, and much more). SMP was also designed into NT from the beginning. You can start seeing the start of these ideas in the MICA design documents but their implementation in C instead of Pillar (variant of Pascal designed for Mica) in NT was definitely the right thing at the time.
https://learn.microsoft.com/en-us/windows/win32/api/uxtheme/...
STAP_ALLOW_NONCLIENT
Specifies that the nonclient areas of application windows will have visual styles applied.This is good, though. The alternative is that the app won't run at all, right? Windows NT is good because of that background compatibility, both for business apps and games.
The alternative is that the application displays with whatever the current GUI uses for its widgets.
MacOS & Linux are nothing like this. You can run most software, as most of the basis for modern software on those stacks is available in source form and can be maintained. Software which isn't breaks.
Apple/Google with their mobile OSes take that a step further, most older software is broken on those platforms.
The way they've kept compatibility within Windows is something I really love about the platform.. but it I keep wondering if there's a way to get the best of both worlds. Can you keep the compatibility layer as an adhoc thing, running under emulation, so that the core OS can be rationalised?
However, it'd be very nice if it did become more of a focus (especially in the glibc/audio/glx areas), especially now that gaming has become very popular on Linux.
Trying to get old, closed-source games like Unreal Tournament to work on Linux can be a real chore.
I strongly dislike the Apple model.
https://www.techmonitor.ai/technology/dec_forced_microsoft_i...
I was wondering for years why MS continued to support DEC Alpha CPUs with NT.
I would agree with that statement in isolation, except by that standard (no need for a syscall per operation) the first “true” asynchronous I/O API on NT would be I/O ring (2021), a very close copy of io_uring. (Registered I/O, introduced in Windows 8, does not qualify because it only works on sockets.) The original NT API is absolutely in the same class as the FreeBSD and Solaris ones, it’s just that Linux didn’t have a satisfactory one for a long long time.
POSIX AIO has usability problems also outlined in the previously linked thread.
Remember, all I/O in NT is async at the kernel level. It's not a "bolt-on".
IoRing is limited to file reads, unlike io_uring.
> As I was looking at the raw system calls related to I/O, something immediately popped out: CloseFile() operations were frequently taking 1-5 milliseconds whereas other operations like opening, reading, and writing files only took 1-5 microseconds. That's a 1000x difference!
This is why DevDrive was introduced[1]. You can either have Defender operate in async mode (default) or remove it entirely from the volume at your own risk.
The performance issue isn't related to sync or async I/O.
[0] https://gregoryszorc.com/blog/2015/10/22/append-i/o-performa...
In Linux, filesystem paths are super-optimized, with all the filtering (e.g. for SELinux) special-cased if needed.
But even still, Windows also had to cheat to avoid completely cratering the performance, there's a shortcut called "FastIO": https://learn.microsoft.com/en-us/windows-hardware/drivers/i...
I wrote a filesystem for Windows around 25 years ago, and I still remember how I implemented all the required prototypes and everything in Explorer worked. But notepad.exe was just showing me empty data. It took me several days to find a note tucked into MSDN that you need to implement FastIO for memory mapped files to work (which Notepad.exe used).
Robert Collins explains that performance is just as good as Linux and the performance loss on Windows is due to file system filters (Defender)[0].
This is what DevDrive intends (and does) fix.
It used to be _much_ slower, like orders of magnitude slower, especially for directories with a large number of files.
To get more of the abstractions out of the way, you want DevDrive. And don't use Explorer.exe as a test bed which has shims and hooks and god knows what else.
https://github.com/maharmstone/btrfs
It's complete enough you can boot and run Windows from Btrfs.
https://lilysthings.org/blog/windows-on-btrfs/
I wonder how many of these limitations affect this, notably performance.
If WSL1 could natively talk to Btrfs without the performance-sapping translation to NTFS, would that resolve the poor Git performance etc?
This impacts performance particularly when working with a ton of tiny files (like git does).
https://speakerdeck.com/trent/pyparallel-how-we-removed-the-...
And yeah, IOCP has implicit awareness of concurrency, and can schedule optimal threads to service a port automatically. There hasn’t been a way to do that on UNIX until io_uring.
In a nicely wrapped PDF :-)
All I/O in Linux is also async at the kernel level! The problem has always been expressing that asynchronicity to userspace in a sane way.
Arguably asyc/await could help with this; obviously it didn't exist in 1991 when Linux was created but it would be interesting to revisit this topic.
Wouldn't that just consist of I/O operations returning futures and then having an await() block the calling thread until the future is done (i.e. put it on a waitqueue)?
With Rust in the kernel this becomes somewhat possible to conceptualize.
You’d probably want to use either some sort of code generation to do the requisite CPS transform[1] or the Duff’s-device-like preprocessor trick[2], but it’s definitely doable with some compiler support. Not in an existing codebase, though.
(Brought to you by working on a C codebase that does express stuff like this as explicit callbacks and context structures. Ugh.)
[1] https://dx.doi.org/10.1007/s10990-012-9084-5, https://www.irif.fr/~jch/research/cpc-2012.pdf, https://github.com/kerneis/cpc
[2] https://www.chiark.greenend.org.uk/~sgtatham/coroutines.html
Unfortunately that's only half-true. You can (and will) still get blockage sometimes with IOCP, it depends on a lot of factors, like how loaded the system is, I think. There is absolutely no guarantee that your I/O will actually occur asynchronously, only that you will be notified of its completion asynchronously.
Also, opening a file is also always synchronous, which is quite annoying if you're trying not to block e.g. a UI thread.
The implication of both of these is you still need dedicated I/O threads. I love IOCP as much as anyone, but it does have these flaws, and was very much designed to be used from multiple threads.
The only workaround I'm aware of was User-Mode Scheduling, which effectively notified you as soon as your thread got blocked, but it still required multiple logical threads, and Microsoft removed support for it in Windows 11.
Nor do they have anything like IOCP, where the kernel is aware of the number of threads servicing a completion port, and can make sure you only have as many threads running as there are underlying cores, avoiding context switches. If you write your programs to leverage these facilities (which are very unique to NT), you can max perform your hardware very nicely.
This is amongst the most important and visible differences between NT and Unix-likes, really. The key idea is that processes manage threads. Pavel Yosifovich in Windows 10 System Internals Part I puts it succinctly:
A process is a containment and management object that represents a running instance of a program. The term “process runs” which is used fairly often, is inaccurate. Processes don’t run - processes manage. Threads are the ones that execute code and technically run.
NtCreateProcess is extremely expensive and its direct use strongly discouraged (but Cygwin and MSYS2, in their IMO misguided intention to force Unix paradigms onto Windows, wrote fork() anyway), but thread creation and management is extremely straightforward, and the Windows threading API is as a result much nicer than pthreads.A process (really, a "task") is a containment and management object that represents a running instance of a program. A program ("task") does not run, its threads do.
The significant difference between Windows-related OS kernels and Unix-y ones is that process creation is much more heavyweight on the former. Nevertheless, on both types of systems, it is threads that execute code and technically run.
However, from the application programmer's perspective, the convention on Unix-likes (which is what really matters) is to fork and pipe between processes as IPC, whereas on Windows this is not the case. Clearly the process start-up time on Unix-likes is considered fast enough that parallelism on Unix until fairly recently was based on spinning up tens to hundreds of processes and IPC-ing between them.
I believe the point stands.
But not for many other kinds of application programming, where you create threads using pthreads or some similar API, which are mapped 1:1 onto kernel threads that collectively form a "process".
I'm not sure what your definition of "fairly recently" is, but in the mid-90s, when we wanted to test new SMP systems, we would typically write code that used pthreads for parallelism. The fact that there is indeed a story about process-level parallelism (with IPC) in Unix-y systems should not distract from the equally fact existence and use of thread-level parallelism for at least 35 years.
A nice historical overview is…
https://developer.apple.com/library/archive/documentation/Da...
https://www.usenix.org/conference/usenix-mach-iii-symposium/...
Linux is the only Unix-like kernel I actually know anything about. In Linux, processes essentially do not exist. You have threads, and thread groups. A thread group is what most of the user-space tooling calls a process. It doesn't do very much by itself. As the name implies, it mostly just groups threads together under one identifier.
Linux threads and "processes" are both created using the "clone" system call, which allows the caller to specify how much state the new thread shares with the old thread. Share almost everything, and you have a "thread". Share almost nothing, and you have a "process". But the kernel treats them the same.
By contrast, processes in NT are real data structures that hold all kinds of attributes, none of which is a running piece of code, since that's still handled by a thread in both designs.
In contrast, Linux threads were implemented essentially as a hack - they were processes that shared memory and resources with their parent process, and were referred to internally as LWPs - lightweight processes.
I also remember a lot of Unix/Linux people not liking the idea of multithreading, preferring multiple processes to one, single-threaded process.
[1]https://en.wikipedia.org/wiki/LinuxThreads
[2]https://en.wikipedia.org/wiki/Native_POSIX_Thread_Library
V->W
N->M
S->T
"New Technology", but yes, it's funny
I just watched it. He does not say what you are maintaining he says.
(I no longer work with Windows very much, but this little bit of trivia has stuck with me over the years)
M->N
Some people point out if you shift characters by one "VMS" becomes "WNT", and give it as an explanation of the name choice of Windows NT, but it's a coincidence. For one thing, nobody ever explains how this gag was going to work back when the project was "NT OS/2"[3].
[1] Virtual Memory System, originally VAX/VMS, later OpenVMS.
[2] Later DEC Alpha, Intel Itanic and now AMD64 systems.
[3] AKA OS/2 3.0 or Portable OS/2.
I don't think it's a concept that meaningfully exists. Microkernels are primarily concerned with isolating non-executive functions (e.g. device drivers) for stability and/or security (POLA) reasons. NT achieves virtually none of that (see e.g. Crowdstrike). The fact that Windows ships a thin user-mode syscall shim which largely consists of thin-to-nonexistent wrappers of NtXXX functions is architecturally uninteresting at best. Arguably binfmt_misc would then also make Linux a hybrid kernel.
WNT = VMS + 1 (next letter in alphabet for all three)
Thread is a way to segregate computation. You spawn a thread and it will run some code scheduled by the OS. you kill/stop a thread and it will stop computation, but not the resources.
The processes section should be expanded upon. The NT kernel doesn't execute processes, it executes _threads_. Threads can be created in a few milliseconds where as noted, processes are heavy weight; essentially the opposite of Unicies. This is a big distinction.
io_uring would be the first true non-blocking async I/O implementation on Unicies.
It should also be noted that while NT as a product is much newer than Unicies, it's history is rooted in VMS fundamentals thanks to it's core team of ex-Digital devs lead by David Cutler. This pulls back that 'feature history' by a decade or more. Still not as old as UNIX, but "old enough", one could argue.
[0] https://stackoverflow.com/questions/8768083/difference-betwe...