For some reason, I suspect it does not run on Windows 1.0 to 3.11 either. I also find it strange to think it would run on both Windows ME and Windows NT 3.5, while excluding Windows 95 and Windows 98. Windows NT 3.5 and Windows ME are nearly a decade apart. The Windows subsystem’s software support in Windows NT 3.5 would be a subset of Windows 95/98.
In hindsight, the progress Microsoft made in the ten years between Windows 3.0 (1990) and Windows 2000 seems incredible. They transitioned from a 16-bit shell running on top of DOS to a fully-fledged operating system with a hardware abstraction layer, preemptive multitasking, permissions, a registry, proper device drivers etc.
Twenty-five years later, there has been basically no progress.
At a minimum, I would have expected something like the Knowledge Navigator
Windows 2000 is my favorite release ever, but anecdotally, I can deny the "no crashes" claim. Sure it was rare, but I had my share of BSODs and weird behavior on it. Still much more solid than... pretty much every other release.
I know, there pretty nice Linux distros that are lightweight and snappy too. One day... :) but not yet :)
To be fair, I have old MacOS laptops that are my wife's laptops, we keep them around because they still turn on, and they have all her old files (I've backed it all up several different ways for her), but I never go on the web with any of the browsers installed on those systems.
Windows NT, which was developed by people (Dave Cutler et al.) who knew how to design and build operating systems (VMS, etc.).
it is by helen custer. it talks about dave cutler's work on it, apart from other stuff.
'Windows Internals' series is the successor to Inside Windows NT.
That exposure allowed them to see how valuable Dave Cutler's PRISM team would be in a total redesign in melding VMS and (whatever tolerable) UNIX features into a new kernel, but focusing it upon Win32.
There were OS/2 and POSIX emulation layers also, but these were obviously second class.
Windows 10 on the other hand will deal with display driver crashes just fine, falling back to safe mode.
compared to what, Linux? the BSDs? Solaris? OS/2 didn't achieve market success but it added major feature subsystems at the same brisk pace.
I also remember 2000 as the only rock solid Windows release, and I never had to reinstall it. XP was very close to that after it fully matured, but nothing feels like 2000.
2000s kernel was one of its better features, but lack of blingy GUI was also helping in its stability IMHO.
Through the life of Windows NT 4.0's life span, MIPS and PowerPC died early, and Alpha support was axed just before the very end. In Windows 2000's development, i386 and Alpha were the only ports left, and Alpha was axed before it could make it to final release.
x86 and Alpha lived simultaneously for most of its development. It wasn't done "first" on Alpha (quite the opposite).
Using Windows 2000 is like using a well-crafted Linux distro. Things just work.
It won't. I see lots of calls to CreateThread/etc in the source. Win32s didn't support threads.
To be honest, though, I very much doubt that anyone has fully tested either that claim or what the headlined article itself claims. A quick look at the source turns up things that require the full Windows NT security model, wide character versions of the API, and threads.
It probably does not run on any version of DOS+Windows, and "except Win95 and Win98" in the headlined article is likely a fumbled way of saying that, which didn't account for those not being the only versions of DOS+Windows that exist.
Win32s was for Windows 3.x only
Win32 for 9x/Me was originally called Win32c, but then Microsoft renamed it to just plain Win32, despite the fact that name was shared by the much more complete NT-based implementation.
Today in 2025, "It runs on all versions of Windows, except Win95 and Win98" comes across as a poetic way to say "we make an effort to support older computers running older versions of Windows."
> MinC is a tiny kernel which runs on Windows. The rest of the software was taken verbatim from OpenBSD, version 6.1. This means that by installing MinC, you run OpenBSD on your Windows machine at native speed.
How does it run this kernel? Presumably (?) it's running in user space, so how do these other tools communicate with it? Are they native(ish) Windows binaries like those built for Cygwin?
I suspect this could be an ingenious technical achievement but it's just hard to tell what exactly it is.
Looking at the source code[1], it appears to be analogous to MinGW in the MinGW:GNU/Linux:Windows relationship, but replace with MinC:BSD:Windows. In other words, a minimal user-mode layer that presents BSD headers (and therefore BSD symbols, macros, and types), libraries, and core utils to end-users, thus abstracting over MSVC†.
EDIT: replace 'MinGW' with 'Cygwin' above. So it is Cygwin.
I'd say calling it a 'kernel' is quite a stretch—there is not much that runs in kernel-mode, and everything runs atop the NT kernel which does the actual 'kernel'y stuff.
[1]: https://github.com/dboland/minc
†: Until one wants to use very recent and very nice Microsoft libraries[2][3], and these fail spectacularly because MinGW doesn't know about nice MSVC-specific stuff like SAL annotations[4].
[2]: https://github.com/microsoft/wil
[3]: https://github.com/Azure/azure-sdk-for-cpp
[4]: https://learn.microsoft.com/en-gb/cpp/c-runtime-library/sal-...
Are you getting MinGW mixed up with Cygwin?
MinGW does not emulate Unix-style APIs on Windows. (Actually I think there are exceptions but that is not its general purpose.) Instead, it is a port of tools aimed at Unix-like OSs (e.g., Make, GCC) to Windows so that they can be used to build source code that is already targetted at Windows. For example, source code compiled with MinGW might include a call to the Win32 API CreateProcess(), but cannot include a call to the Posix API fork().
Cygwin, on the other hand, allows compiling source code intended for *nix to native Windows binaries. For example, it compile code that calls fork(), getuid(), stat(), etc. It has that user-mode emulation that you mentioned (e.g. mapping between Unix-style UIDs and Windows SIDs), which happens in cygwin1.dll.
I think you're right, this is probably the BSD equivalent of Cygwin.
That being said... I feel the distinction is very blurred, and even more so with the inclusion of MSYS. It seems very few people use naked MinGW, despite a few distributions[1][2] being available.
For instance, MinGW also provides `unistd.h` and `pthread.h` on top of `windows.h`. Certain distributions of MinGW provide lib{std}c++ instead of MSVC STL. Where does 'build native Windows executables from source files that are already targetted at Windows' stop, and 'allows compiling source code intended for *nix to native Windows binaries' begin?
Also, based on my comment above, MinGW doesn't do a great job at 'already targetted at Windows', because some very core libraries that rely on fundamental Windows-y constructs don't work. Personally I avoid it because of its incompleteness, and just use straight `clang++.exe` from the Windows LLVM release[4], aside a full install of the Windows and MSVC SDKs.
[1]: https://github.com/skeeto/w64devkit
[2]: https://github.com/mstorsjo/llvm-mingw
[3]: https://github.com/llvm/llvm-project/releases/download/llvmo...
Cygwin strives for certain Linux compatibilities; the project's motto, right under the title on the cygwin.com page, is "Get that Linux feeling - on Windows".
The userland in Cygwin is based on GNU Coreutils, and such.
MinC is going for a BSD userland; its motto could be "Get that BSD feeling - on Windows".
Anyway, I'm sorry I've distracted away from your core point: as you've said, despite its name, it seems MinC just provides a user-mode API layer, just like Cygwin does.
Under Cygwin, you can compile programs in the MinGW way, but you can also use any build-time tool that will compile on Cygwin.
Getting a build-time tool for MinGW means porting it to MSYS; have fun!
Granted that was hundreds of hours, some patches (only 8 lines though), and probably a bit of masochism.
I did of course need MSYS2 command line utilities like make and bison to run the GCC configuration/make scripts. Although we use the mingw32 version of make along with the cross-compiler which also has no other dependencies (it uses cmd.exe as a shell if you don't have a bash.exe in your PATH).
Side-tracks and tangents are the powerhouse of HN comments ;)
As for MinGW and Cygwin (and all the other *nix-on-Windows stuff), I take a bit more lower-level view than what (developer or user) environments they provide, or what tools they use.
In a nutshell, C++ binaries compiled with MinGW are binary-incompatible with C++ binaries compiled with MSVC, because they are built against different binary interfaces: x86_64-pc-windows-gnu (or x86_64-w64-mingw32, which appears to be a synonym) and x86_64-pc-windows-msvc respectively. The former is the C++ Itanium ABI, the latter is a partially-documented MSVC ABI.
Cygwin is an 'ABI' of its own too, because everything needs to be linked against cygwin1.dll, and when it is missing there is a runtime error. WSL1 and WSL2 from an ABI standpoint are indistinguishable—they are x86_64-unknown-linux-gnu.
This is sort of why we can have LLVM-MinGW, which is the entire LLVM suite and only LLVM binutils (see my parent comment for a link), without nary a GNU binary. It's essentially Clang, built to target the MinGW ABI (this can be built on Windows with MSVC, oddly enough).
Speaking of Linux, every glibc upgrade is essentially a different ABI (for some functions) presented to the developer—so much for Linus' assertion of 'don't break userspace'. Even if the kernel doesn't do it, the entirely user-space C library will do it for him. Oh, and musl libc is yet another ABI.
I have delved too far into the weeds of cross-compilation, and as a result I can't help but absolutely despise everything about the C and C++ ecosystem.
MinGW is a GNU toolchain for writing Windows-native software... that happens to be used quite often to compile Unixy non-Windows software, so they added MSYS which is derived from Cygwin and works like Cygwin (a DLL providing POSIX APIs implemented using Windows APIs), to make it easier to compile and run Unixy software unmodified.
WSL is a VM that runs your choice of Linux kernel and distro as a guest OS, and adds integrations with the host system that make it seem much more native than it really is.
Yeah, I thought that too, and said so in an article. It would be the clean, logical, elegant way to do it and inline with the history of NT.
I got angry denials from several Microsofties on Twitter!
It isn't at all.
WSL1 is an offshoot of the now-cancelled Android runtime for Windows.
They wanted to run Android's JVM/Dalvik apps on Windows Mobile... but discovered more and more native OS calls. So, they ended up implementing 90% of a Linux kernel emulator in userland.
Later, they made it standalone and complete enough to run a real Linux userland on top, and marketed it as a Linux runtime.
It is tragic to me that senior MS execs are now proud of this approach and scolded me for thinking otherwise.
My conclusion is that MS no longer has:
• Any kernel engineers who really understand how NT works deep down;
• Anyone skilled enough to modernise the NT kernel's POSIX personality to be Linux personality;
• Anyone in authority who realises it ought to have these things;
• Nobody left who feels shame at this.
[1] https://learn.microsoft.com/en-au/archive/blogs/wsl/pico-pro...
Particularly for the more complex cases of container APIs, GPU access, desktop integration, etc. Those are solved problems in the VM space and reinventing new solutions at a slightly different layer is not necessarily wise or realistic.
For my use cases, I just want to target unix-like APIs and use bash-isms so I can reuse my build scripts and tooling. I don't really care if the binary format I consume or compile to is different to Linux - as long as my development experience is identical across MacOS, Windows and Linux.
A thin layer on top of Windows that mimics Linux so I can run bash _properly_ is all I really need.
The closest I've come is using Msys2 with zsh and uutils and it is so close but there are still cases where it simply doesn't work. WSL1 was pretty close but it falls short by needing remote development tools and having isolated storage/poor performance interacting with host storage.
WSL2 is DOA for me, I just hand roll my own Linux VM and call it a day.
For example, if you were a Unix archiver extracting a file, you'd call stat() open() write() close() chmod() utimes(). On Linux/BSD that's 1 file open/close, but on Windows, that's 4 file opens/closes because the Windows APIs need an open filehandle, while the POSIX APIs take a filepath. Linux/BSD have LRU caches of filepath->inode because they're designed around these APIs, Windows doesn't. Cygwin has to open/close a Windows filehandle each time because it can't make the calling code pass a filehandle instead.
So it may be more comfortable and familiar, but also Windows APIs are unsympathetic to code designed for Unix originally.
See this talk on how the developers of rustup massively improved their performance on Windows by restructuring their code: https://www.youtube.com/watch?v=qbKGw8MQ0i8
https://learn.microsoft.com/en-us/windows-hardware/drivers/i...
I know conventional VMs do this kind of thing too, but I've always found it more awkward to set it up, you have to install special tools or kernel modules, etc. With WSL it just works out of the box.
That has to be sarcasm, right?
Then again, I see WSL as a poor man's Linux ("poor man" being a developer in some enterprise who can't pick their tools freely due to some IT policy).
And while WSL is worse than Linux without Windows, I still prefer it over MacOS with Linux running in a VM.
The one exception: my God filesystem performance on WSL1 was ass, and not an easy problem to fix
Something like skeeto's w64devkit? https://github.com/skeeto/w64devkit
Unfortunately this was cripplingly slow for use in e.g. Git, so they moved to a model which is more of a VM.
The insurmountable problem was file system semantics. In Linux, files are dumb and fast. On Windows, files are smarter and therefore also slower. Linux applications expect dumb fast files and they produce a lot of them. Mapping Linux file system calls to Windows file system calls is doable but you can't overcome that difference.
At that point, simply virtualizing the Linux kernel itself is an obvious better solution long term.
This is a common confusion. WSL1 is not deprecated, and both WSL1 and WSL2 continue to be developed and supported in parallel by Microsoft.
This is example of bad Microsoft marketing. Maybe they should have added a postfixes instead of numbers: "WSL-native" "WSL-VM" or something like that
I have had a 'Softie deny, in person to my face at the Ubuntu Summit, that any further development would occur on WSL1, in 2022.
So I have to call [[citation needed]] on that.
Nah. It was fine.
Filesystem access was slow. That meant that Git was slow. And every Linux techie thinks they're the next Torvalds and hacks on code and uses Git, so Git needed to work well.
But it is the case that you can build a Windows application from source on Linux and link it with libwine, in the same way you can build a Unix program from source on Windows and link it with cygwin.dll -- I seem to remember some time ago CorelDRAW (or at least Corel Photo-Paint) was made available for Linux that way, officially supported by Corel.
Maybe start with an explanation of what it does without referring to Cygwin? That would be for people unfamiliar with Cygwin. Edit: actually you already did that, but starting off with “not Cygwin” is confusing.
You could also explain how your approach differs from Cygwin, for people who do know it.
So what happens when you "boot" MinC? It sounds like it runs all the usual OpenBSD services and what not. But are all of those new Windows processes, or just new threads in the one MinC process?
Also, do processes inside MinC get to interact with the Windows host filesystem and networking in any way?
BTW, this is very cool!
The "kernel" referred to at that link is a full actual kernel, with networking, proceed scheduling, device drivers and hardware access, etc. It means the full implementation of those features. The reason it can be linked into the application's process as a library is because it's taking about a situation where there's only a single application running on the whole machine (presumably a virtual machine). The kernel and application then run together in a single memory space, with the kernel code (maybe the whole thing?) running in kernel mode.
You have implemented the user mode API that makes system calls to the (Windows) kernel. That is not a kernel in any sense. It is confusing and wrong to call it a kernel.
Still pretty cool but overshadowed by the claim that they've written a whole kernel.
"to run in a separate kernel space" You emulated those interrupts, and they really run in a separate kernel space [1]? Or you mean it's emulated as if it runs in a separate kernel space?
If it's really running in kernel mode, as you are literally saying, how is it doing that? Is it running in some virtual machine manager like Hyper-V or as something like a driver in the Windows kernel? How does it interact with the hardware e.g. does it access the same file systems that Windows does, and how does it coordinate that?
Looking at the source code I don't see any references to the Windows WDK / DDK (driver development kit) but a lot of references to user-space Windows API functions. I also don't see most of the actual BSD kernel [2]. For example, could you point me at the process/thread scheduling code (like sched_bsd.c [3])? Are you sure it's a kernel? Are you sure it runs kernel space, not user space after all? It seems like it might actually be an abstraction layer that emulates the user-space BSD system calls but runs in user-mode and make use of (only) the Windows kernel. If so, what do you mean by "emulating an interrupt" - how are you intercepting them? If you're just providing the C API functions to link into the application, and that don't actually trigger those interrupts at all, that is something a lot less ambitious. Still something impressive and worthwhile but you're setting readers up for disappointment if you describe it as something that it isn't.
That is what Cygwin does by the way. It implements POSIX APIs in user space. It does not claim to be a kernel (because it's not) or to run in kernel mode (because it doesn't). The thing is, I can understand you may have chosen the name "MinC is not Cygwin" because it works in roughly the same sort of way as Cygwin but is a different implementation. But the name, along with the description as being "a tiny kernel", suggests that it's not Cygwin because it works in a fundamentally different way, i.e., running the actual BSD kernel in actual kernel mode.
[1] https://en.wikipedia.org/wiki/User_space_and_kernel_space
[2] Mirror is available at: https://github.com/openbsd/src/tree/master/sys/kern
[3] https://github.com/openbsd/src/blob/master/sys/kern/sched_bs...
For starters, I needed to put the code of my kernel emulation (libposix-6.1.0.dll) at a specific memory address in order to get that snappy feeling when you start an OpenBSD program. Normally, 32bit DLLs in Windows are loaded at 0x10000000 (called the "ImageBase"). This causes the Windows kernel reposition the DLL because in most cases, other DLLs are already loaded there. In my case these are netapi32.dll, ws2_32.dll, iphlpapi.dll and shell32.dll among others. Making my DLLs load at an address just below the 0x10000000 boundary makes MinC programs load faster, in effect creating a space for my kernel, e.g. "kernel space".
Secondly, I needed some mechanism to reset the contents of the CPU's registers after calling into the various Windows DLLs which are not part of the Windows NT kernel. For instance, the WriteFile() function changes the %edx register, which is used by the GCC compiler to contain the high part of 64bit variables. Turns out I needed what is called a "context switch", saving the contents of all registers onto the stack, calling my kernel emulation and then restoring the registers from the stack. In Linux, this mechanism is triggered by a special interrupt (int 0x80). I decided to name the function that does this in my kernel emulation "__kernel", so in assembly I can write "call ___kernel" [0].
There is more, but I won't go into that right now. I plan to do a write-up on the topic. By the way, Microsoft also has a user space implementation of their kernel, called kernel32.dll, implementing Win32 APIs in user space.
[0] https://github.com/dboland/minc/blob/master/libposix/arch/x8...
What you've done is very impressive. But, as I've said elsewhere, it's overshadowed by you insisting on calling it a "kernel" when it's not. Please stop doing that, and please don't include that claim in your future write up of how it works. The thing is, some submissions to Hacker News are by people who really have written their own actual kernel so readers have no reason to doubt your claim. Many will believe you really have written (or ported) an actual operating system kernel and then be disappointed when they realise you haven't, rather than excited by what you have achieved.
> My kernel is implemented in userspace
Your kernel is not implemented in userspace, because you have not written a kernel. User mode Linux is an actual real kernel running in user space. It is just a totally different concept.
> I should use the term "kernel emulation"
No, you shouldn't. This is coming a bit closer to the truth but still wrong. You have emulated **the system call interface** of a kernel. The implementation of the system-call interface is only a teeny tiny part of a kernel.
> ... the code of my kernel emulation (libposix-6.1.0.dll) …
You mean, the code of your system-call interface emulation.
> Making my DLLs load at an address just below the 0x10000000 boundary makes MinC programs load faster, in effect creating a space for my kernel, e.g. "kernel space".
No, that is not "kernel space". None of those DLLs (netapi32.dll, ws2_32.dll, iphlpapi.dll and shell32.dll) are part of the kernel. They all run in user mode. Please read the Wikipedia article on user mode vs kernel mode that I linked to above, and understand that none of your code is running in kernel mode at all.
> By the way, Microsoft also has a user space implementation of their kernel, called kernel32.dll, implementing Win32 APIs in user space.
kernel32.dll does run in user space but it is not a kernel or an implementation of a kernel. Its name is a historical artefact. (Its name can be traced back to a component that, 40 years ago, in Windows 1.0, actually was a kernel. But even by Windows 3.0 it was already just an interface to some kernel services, not a kernel implementation.)
> ... after calling into the various Windows DLLs which are not part of the Windows NT kernel. For instance, the WriteFile() function ...
None of these DLLs are part of the kernel! (By the way, "WriteFile()" function is implemented in kernel32.dll. But it's still not part of the NT kernel.)
> Turns out I needed what is called a "context switch", saving the contents of all registers onto the stack, calling my kernel emulation and then restoring the registers from the stack. In Linux, this mechanism is triggered by a special interrupt (int 0x80).
No!
* "Context switch" means switching between user-mode processes, not between user mode and kernel mode. It is done by the scheduler within the kernel.
* int 0x80 triggers a system call on Linux, not a context switch.
* A system call doesn't trigger the save/load of registers, as you said. Instead, you need to save/restore the registers yourself. (i.e., to make a system call on Linux you would do: (1) stash registers on stack; (2) call int 0x80; (3) restore registers.)
* Saving registers and restoring them is part of many function calls, not just system call interfaces. It's just that usually the compiler takes care of it for you, rather than something you need to hand craft in assembler.
--------------
Here's how I'd attempt to describe what you've done in a way that isn't misleading:
Typically, if you're going to going to emulate the user-mode API of one operating system within another, you'd simply implement the user-mode functions of one directly in terms of the other. For example, you might implement the Posix open() API by reformatting the arguments and directly calling the Win32 OpenFile() function. In MinC, the user-mode API is instead emulated at the system call level. This means that the user mode DLL (libposix-6.1.0.dll) has the same code as the user-mode API in BSD except that the system-call interrupt is replaced with a call to the syscall emulation code.
By which I mean, completely understandable to pick a version and stick with it. If I were trying to develop a tricky layer replacement that is what I would do. However it is also tempting to try to follow upstream. I wonder if one of obsd's infamous breaking innovations actively interfered with the project.
For those unfamiliar, where Linux has a "don't break user land policy" and this is fine and good for a project like linux. It does mean that the linux project is terrible at handling needed user land breaks. Where OpenBSD's policy is more "we got really good at breaking user land" They are so good that most of the time the users don't notice. But I would not want to try and ship closed source commercial software targeting obsd.
That’s good. It’s an interesting project and the discussion here is overall very interesting. Thanks for posting it.
Take networking, one of the screenshots shows the output of ifconfig. That teaches you almost nothing about Linux networking, because ifconfig in Linux and OpenBSD are two very different tools, and you'd probably not teach people to use ifconfig on a modern Linux distro. Same for the boot process... rc and systemd are not the same, not even close.
It is a very cool project but almost all references to Linux is wrong.
The word "Linux" only occurs on the page once.
Notably, from a teaching "Unix tools 101" perspective, the difference is super unimportant. If the author's goal is to get students to open a terminal for the first time in their lives (on their Windows laptops!) and type some ls commands and maybe pipe stuff into sed once or twice, they can learn this on a BSD and apply it in any Linux (or the reverse) just fine.
I think the author means it literally. His goal is to teach students some Linux basics, and his method is to put a BSD into their Windows. It's kinda nuts, but you gotta agree it's kinda "mad genuis" nuts.
A proud cygwin user myself, with cygwin in the PATH since the 2000s, I recently sideloaded Ubuntu under wsl.
Right now, wsl is my primary terminal app, I've mounted C:\ as /c, added a symlink to bypass the ugly Onedrive default name, and... I'm happy.
Slowly, I removed 90% of the mixed BAT scripts, converted to bash the rest, and I now enjoy it.
As the old timer that I am, I limp around powershell, so no luck with that.
Cygwin on the other hand seems to be slowly dying, as more and more packages are now unsupported/unmaintained, with Redhat apparently willing to smother it at the first viable moment.
Any thought?
I'd experimented with several of these before I realised that what I wanted wasn't Windows running Unix-like utilities, but a real honest-to-goddess Unix system, which was spelled "Linux".
it's based on MSYS2, so it's native. maybe you should check this one out.
Wouldn't it be better to either teach BSD with current toolset, or to use GNU tools to teach Linux?
If anybody wondering.
https://en.wikipedia.org/wiki/Cooperative_Linux
Interestingly, Wikipedia claims that User-mode Linux inspired Cooperative Linux.
Maybe UML can run on top of MinC?
Does MinC accepts ELF linux binaries?
<https://web.archive.org/web/20250423103309/https://minc.comm...>
There was a January 2024 HN submission requesting feedback by thingfish suggesting early work at roughly that time:
<https://news.ycombinator.com/item?id=38951099>
Thingfish: Adding creation / last modified dates would be helpful.
A recently-released project may be intriguing but something risk-averse entities (individual/organisations) might prefer to hold back on for fear of, let's call it "infant death syndrome".
An old project with no active development is generally perceived as "dead", with risks that security- or bug-fixes could remain unaddressed for long times, or that there may be current zero-day exploits possible.
An old project with a healthy activity stream counters both points: the project has exhibited staying power and addressing ongoing maintenance concerns. Even active projects might give caution (say: feature creap or enshittification), but that's beyond the scope of merely giving initial / latest activity timestamps.
NB: I've well over 30 years of professional IT experience in shops ranging from small operations to multi-billion-dollar firms. Advocating for, or against, various technologies and solutions is a large part of that role. It's also something that carries into my choices for my own personal systems.
I'd be unlikely to do much with MinC myself as I don't use MS Windows, though it fits in with a long tradition of similar tools I have used, often with fond memories, including Cygwin, David Korn's UWIN, MKS Toolkit (Mortice Kern Systems, licenced by Microsoft for early versions of WSU, precursor to WSL, I've just learned), VMWare, Xen, qemu, Virtualbox, Parallels, etc. These have different architectures but all basically address the problem of "run programs from OS X on OS Y", which turns out to be a fairly-frequently-encountered challenge. I might well recommend MinC to those with such needs.
Cygwin itself is really easy to install, you can just copy the folder around, you don't need the installer.
Oh, ah, _task_copy(). You swap stacks... I think because of course.
Your execve() is real though, since you use CreateProcessAsUser(), which is good.
The compromise you made is pretty neat, though obviously some things might not work well. Though I'm guessing this is working quite well for you.
Your file names are weird; they often tell me nothing about what to expect to find in them.
I looked for fork() because that's the difficult one to implement on WIN32. What Cygwin does is some crazy gymnastics that sometimes fails. You might know that I think fork() is "evil" [0], or if you hadn't, you do now, and I guess you're likely to agree with that take, but I'd love to hear your thoughts on that, because clearly you've thought about fork().
I've to say that you've clearly thought a lot about this, and though I've not tried it (and probably won't) you seem to have done an excellent job.
[0] https://gist.github.com/nicowilliams/a8a07b0fc75df05f684c23c...
Thank you. I needed that. I started the project in 2016 and have been obsessed with it since then. The weird thing is that I never had to use workarounds or hacks that are mentioned by the Cygwin team [0]. For instance, the select() call does map cleanly on top of the Win32 API. I just needed to use WSAWaitForMultipleEvents() instead of WaitForMultipleEvents() (the other "easteregg"). Why the Cygwin people didn't figure this out baffles me. I guess their current code base doesn't allow the rewrite. My big breakthrough was when I realized that the "inconsistent interfaces" [1] in Win32 file handles can be implemented as virtual file systems. One for each handle type (char, disk, pipe, etc). That was my "throwing away 1000 lines of code" [2] moment.
As to the weird file names, I use the file names OpenBSD uses. My rule is to always use the file name of the header (.h) file where the system call is declared in OpenBSD. I also use their struct and constant names, prefixed with "WIN_".
The "fork is evil" thing is discussed a lot in the programmers community. I myself find it quite clever. Threads are highly volatile and are very hard to program without running into race conditions. The solution is to make a copy of everything the child will be using: duplicate file descriptors, the stack, globals (rss). The kernel does all this for you in one system call. I often wonder how the people who complain about the absence of real concurrency in their programming languages [3] actually would use this feature. In my opinion the best way to use concurrency is to string individual programs into a pipeline. This will never go "evil" on you.
[0] https://cygwin.com/cygwin-ug-net/highlights.html
[1] https://www.usenix.org/legacy/publications/library/proceedin...
[2] https://skeptics.stackexchange.com/questions/43800/did-the-c...
Well, like I said, I'm impressed.
> I myself find [fork()] quite clever.
Oh for sure it is clever. Though vfork() would have been more clever. The thing that fork() did that was very nice is make it real easy to spawn processes in a shell, which meant not having to design a spawn() system call (which are invariably large APIs), which greatly simplified Unix development in the 70s, both kerne-land and user-land. vfork() would have been more clever, but that didn't occur to Ritchie, Thompson, et. al. I wonder how things would have gone if they had thought of vfork().
They expose a dark secret behind the fork() call and I felt it too when implementing it myself. Almost gave me a heart failure. So here's my simplified take: what if the parent did a malloc() and put the resulting pointer on the stack (which is what git does, BTW). A simple copy of the stack to the child wouldn't be sufficient. The kernel then would have to follow the pointer, malloc() new memory and copy the data. It's not hard to see where this is going. What if there is malloc()ed memory in this copy? It's madness. I suspect this could bring a whole system to its knees.
This is a problem a kernel should not try to solve. Only user space knows about its application of memory. While reading the source code of the software I include in MinC, I always thought this is bad programming, perpetuated by Torvalds' #1 rule "don't mess with user-space", leading to things like copy-on-write.
This all leads me to believe I can get away with doing flat copies of stack and globals during fork(), implement spawn(), never implement copy-on-write and patch the userland code if needed. Am I right?
[0] https://www.microsoft.com/en-us/research/wp-content/uploads/...
Haha, well, tricking you was not my intent. I'm glad I did though!
> The kernel then would have to follow [...]
The kernel doesn't have to do anything like that because the kernel doesn't know about user-space allocators. The kernel only knows about the pages used in constructing the user-land address space for the process. What you're really getting at is "fork-safety" (like thread safety, but fork fork()).
Whether using fork() or vfork(), in principle the child[0] process is only permitted to use async-signal-safe functions on the child side. It can only use async-signal safe functions, which are typically the system calls needed to do everything up to an execve() (which is also safe).
In practice however, many of us know how to write multi-process daemons that do very much use async-signals-UNsafe functions on both sides of the fork(), and it's OK if you know what you're doing, and if it's a _real_ fork(). If it's more like like a combination of threads and vfork() then it's not safe at all to use async-signal-UNsafe functions on the child side!
And malloc() (and free()!) is absolutely NOT async-signal-safe! Which is what you noticed in thinking about this.
So a fork() that creates a new thread but not a new address space, and which swaps the stack back and forth as each of the parent or child execute, is NOT safe to use with async-signal-UNsafe functions on the child side of fork().
So your fork() implementation, if I understood what it does, is probably only safe for a certain class of programs that happen to be using fork() exactly as the fork(2) man page says.
So you might need to patch some fork()-using OpenBSD programs to function correctly in MinC. And any other fork()-using programs one might want to use under MinC may also need to be patched.
Programs using posix_spawn() will be OK _if_ OpenBSD's implementation uses vfork() and the MinC kernel implements vfork().
With vfork() the danger of using anything other than async-signal-safe functions on the child-side is so much clearer that it is paradoxically and in my opinion safer than fork().
Although I called fork() "evil", I use it lots in my code. I've written many versions of daemon(3) that have the parent exit only when the child signals that it is ready (this is to avoid race conditions in multi-service systems and testing). I've written multi-processed daemons that do use async-signal-UNsafe functions on both sides of fork(). But I don't really condone that :cry-laugh:. One has to be quite aware of the dangers, and understand them, in order to use fork() like that.
BTW, I think it would be interesting to have a new try at implementing fork() in WIN32. I wonder if one can create a copy of the parent's address space in the child w/o having to use any of the LoadLibrary*() functions to load DLLs, thus avoiding the ASLR issues for example. I imagine that it must be possible, but also that it must be very tricky. You can see that abandoning fork() for vfork() and spawn-type APIs would be best for running Unix software on Windows...
[1] is an implementation of daemonization that spawns a child instead of fork()-and-continue. That has an option to exec on the child-side to make it possible to test on Unix logic that otherwise would only be tested on Windows. One could use the same approach to build multi-processed servers, where you'd spawn each child rather than fork() each child -- i.e., vfork() then execve() with a special command-line option or env var to indicate "you are a worker process". OpenSSH's sshd nowadays always execs on the child-side of fork().
[0] daemon(3) inherently violates the requirement that the child-side of fork() not use async-signal-UNsafe functions, but this is OK because the real [but unstated] requirement is that only one of the parent or child may use async-signal-UNsafe functions.
[1] https://github.com/heimdal/heimdal/blob/master/lib/roken/det...
Incidentally next week I have to debug one of our tester's laptop - he installed vmware which stopped WSL from running somehow and now neither option works.
I have free access to entire FS, I can run Win32 console tools as well inside bash. If I want true Linux environment, I can always spawn VM and use Xserver on Win32 to work on it (Xming).
It's so easy to run a Linux VM under Windows, I don't understand avoiding it. There's a little to learn, yes, but then you have real Linux as opposed to dealing with the inevitable differences between Linux and any of: Cygwin, MinC, WSL2, or MacOS.
?
Linux is something else entirely, a student's project to make a MINIX compatible kernel, usually packaged with the GNU operating system, which like BSD aimed to be Unix compatible, but notably is not Unix (It's right there in the name: GNU's Not Unix).
It's usually packaged as a part of the Android operating system. GNU hasn't been the popular userspace for a long time.
This explains people who argue that Android is not Linux, despite it featuring a Linux kernel and self-identifying as so: They are intending to say that Android is not POSIX.
We need to make POSIX (as concept/word) more popular.
Time to ask an AI ?
As an obligatory warning, if you have never seen Computer Stupidities previously, expect to lose a day reading it.
WSL requires Windows 10 or 11 though.
I'd also guess 'telemetry' pumps out all one does in WSL, while this might leak less of what the kids are doing.
https://www.reddit.com/r/rust/comments/vtc0fy/wsl2_faster_th...
There have been others who observed the same in the past (and with WSL1), although I do not have a list. I recall reading libc telemetry hooks on Windows that are absent as being claimed to be the cause, but I cannot find the page where I read that. The Reddit post has the alternative suggestion that process creation speed is the cause.
Performance on my bare metal Linux machines is even better. Do you consider this to be sufficient proof that WSL has telemetry hooked into it?
Don't assume anything in shells except POSIX sh.
Unfortunately there are people who think Linux is the only way.
After all, if you learned to do "linux" on OpenBSD you'd be pretty much at home on Linux, too.
It's a clever bit of SEO, too, mashing in Cygwin, Linux and OpenBSD in the copy.
The Worst Job in the World, from Michael Tiemann <tiemann@cygnus.com>:
https://www.donhopkins.com/home/catalog/unix-haters/slowlari...
PS: Fuck Trump supporting anti-vaxer Scott "You have zero privacy, get over it" McNealy. May he run Solaris in hell.
Scott McNealy has long been one of Trump’s few friends in Silicon Valley:
https://www.sfchronicle.com/politics/article/Scott-McNealy-h...
Former Sun Micro CEO Scott McNealy, known for his provocative quotes, says Trump is doing a 'spectacular job' amid the coronavirus crisis. That's not how many tech experts see it:
https://www.businessinsider.com/scott-mcnealy-praises-trumps...
Sun on Privacy: "Get Over It":
Mingw
WSL seems to be new now
Cygwin
And this one.
It's nice, but not perfect. It inherits a lot of problems from Cygwin. File access is still slow (as mentioned in other threads) and symlinks don't behave right (by default making a symlink creates a deep copy of the target, and even NTFS symlinks need to know whether the target is a file or a directory; either way you cannot create a symlink when the target is missing, and this causes rsync to fail, for example.)
MSYS2's strength is as an environment for compiling cross-platform apps for Windows, and I would recommend WSL2 for anything else.
Re: "Cygwin…plus several other environments[+]", the second paragraph of MSYS2's home page summarizes it pretty well:
Despite some of these central parts [Bash and cli tools] being based on Cygwin, the main focus of MSYS2 is to provide a build environment for native Windows software and the Cygwin-using parts are kept at a minimum.
[+] https://www.msys2.org/docs/environments/There are several different environments, each with their own different and incompatible set of packages. When you run "mingw64", you are running a different environment than "msys2". If you install a package named "gcc", you are getting the "gcc" intended for "msys2", and not the package intended for "mingw64".
The "Msys2" version ships with Windows headers that are not compatible with some Windows programs, while the "Mingw64" has compatible headers. Then this led to me filing an invalid bug report.
The role of the different environments (with their color-coded icons), and the necessary prefixes to install packages for those environments could be made a lot clearer. And that if you are in the "Msys" environment, all software you build will depend on "Msys".
WAT? Linux == OpenBSD now?
Duration: 00:00:21.20, start: 0.000000, bitrate: 307 kb/s
Stream #0:0[0x1](und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(progressive), 960x672, 306 kb/s, 10 fps, 10 tbr, 10240 tbn (default)
so maybe in a comically ancient version of Android, or perhaps a "hardened" distro that eschews modern stuff?Merely as another datum, I did URL surgery to get the prior .webm flavor and it's blank for my FF 137 on macOS so there was obviously something else going on (by blank I mean it had 21 seconds worth of black pixels, not that it didn't play)