This shows that having a legal way to run outdated operating systems is always important to guarantee that old software runs exactly as intended. Online activation schemes make this problematic.
The solution seems to be installing and fully activating the operating system in the VM while it's still possible, then archiving the VM image. However, I don't know how reliable this method is, since the Windows OS may require reactivation if the hardware configuration changes significantly. Therefore, if the future VM host machine exposes slightly different hardware to the guest machine, the activation might be gone.
This particular example actually doesn’t show that. The misbehavior is caused by a bug in the original game, which was initially hidden only by pure chance, and was already fixed 20 years ago in updated releases of the game, and can be fixed in any version by adding the missing parameters in a plain-text asset (or running the existing patcher add-on).
I agree in the general case, but this particular case isn’t a good argument for it.
I would argue that this case also demonstrates the aforementioned problem. Apparently, an older version of the Windows OS was tolerant to this specific bug, and the game worked just fine. Future users might not be even aware that an updated release of the game fixed this bug, or they might not have access to the update.
You can't blame the user for the fact that the old software contains something that is, technically, an invalid use of the API, meaning the software shouldn't have worked, even in the past. The only way to reliably make the old software work as intended is to have an OS version from that time available.
Hopefully the "Stop Killing Games" movement will create some formal obligations around those activation schemes too since it's pretty much the same problem from a different angle.
Criticisms of his post aside.
Isn't it unfortunate, the absolute degree everything legacy is at least in some way tethered to windows. If only there had been an open alternative, it would allow huge communities to emerge keeping very old software/games working indefinitely. Not that linux was even remotely close to being usable even only twenty years ago. Relying on a giants benevolence is never going to work in the long run. Their contemporary direction is only a function of what side of the bed theyd like to turn on today.
How would an open operating system fix a bug caused by sloppy game developers? I don't think anyone would think "let's not optimize the (equivalent of) critical sections in our operating system so that we don't break GTA", unless you're suggesting providing 100s of different implementations of different parts of the operating system that people can choose from to run a specific game, which I don't think is viable either. Patching individual games is far easier and is actually viable, which is precisely what GOG (Good Old Games) successfully does on a significantly large scale.
If anything, what Microsoft was way, way better at was finding and working around these types of problems in the OS. Many developers have a more idealistic and less pragmatic approach instead of empathizing with their users: "it's the program's fault, why should we deal with it?"
> unless you're suggesting providing 100s of different implementations of different parts of the operating system that people can choose from to run a specific game
> it would allow huge communities to emerge keeping very old software/games working indefinitely.
That's a completely backwards take though. Windows is practically the only platform in the world that cares about backwards compatibility. On Windows you can run a 20 year old executable and you've got pretty good chance it runs. With Linux operating systems you have no idea if something compiled on the last LTS release runs on the next one.
This is one of the few issues where having a private company control the entire stack and providing a stable ABI for decades is actually a benefit, to the point where your target if you want to build games on linux is...Win32 (https://blog.hiler.eu/win32-the-only-stable-abi/)
> it would allow huge communities to emerge keeping very old software/games working indefinitely
The Linux community already stumbles at this and needs Windows to help it out. "Win32 is the only stable ABI on Linux" has been said so many times it isn't a joke any more. Keep in mind that the OS being open doesn't make the games open. Wine is possible because of Win32's die-hard commitment to long-term binary compatibility. I'm not so sure we're in a bad situation here. The Linux userspace has never had this degree of backwards binary compatibility. The kernel doesn't break userspace but userspace breaks itself all the time.
Linux userspace gets lots of other benefits from this rapid-iteration approach that doesn't concern itself with literally decades of binary compatibility, but keeping old games running indefinitely isn't one of them.
> Not that linux was even remotely close to being usable even only twenty years ago.
Running Linux on regular consumer hardware in 2005 was not really any harder than it is today. In fact, many of the same problems still exist! GPU drivers and janky wifi and power-saving modes, same shit, different decade.
There's Steam Deck now, and Android, but those are still quite proprietary driven by single companies, so I'm not really sure they fit what you mean about an open alternative.
> Not that linux was even remotely close to being usable even only twenty years ago
I've been using Linux only as a desktop for 30 years, so that's a strange comment. For sure games and other software that was written to run on Windows exclusively, ran best on Windows (who could have predicted it!). But as a desktop, Linux has been usable for many decades.
It works for some domains, but, games ain't the only thing. There is a lot of business software and "technical" software (for controlling manufacturing machines or whatever), which runs on Windows only, as it is the "default" platform. And those applications are low quality special purposes software, nobody knows much about ...
> Windows is actually excellent at maintain backwards compatibility.
Rather: Windows is actually excellent at maintain backwards compatibility for binary programs.
There exist lots of other backwards-compatibility topics like
- being backwards-compatible in the user interface (in a business setting, ensuring that the business-critical applications still run is a problem of the IT, but if the user interface changes, people will complain. I just say "Windows 8" or "Office ribbons" (when they were introduced)). I would for example claim that very specifically for the shell interface, the GNU/Linux crowd cares a lot more about user-interface backwards compatibility than what Microsoft does.
- being backwards-compatible in the hardware requirements (i.e. "will it still run on an old computer"). I just want to mention the drama around Windows 11 because it doesn't run on still actively used hardware so that Microsoft cannot force the update on all Windows 10 users, but on the other hand wants to terminate the support for Windows 10.
Also, Windows containers are a thing (not that I’ve ever used them). Shouldn’t it be possible to containerize old games bundled with versions of win32 libraries that were stable when the game was released? Then the games could be run in perpetuity so long as the low-level interfaces needed by the container runtime is maintained.
People say this but I really don't consider it to be as true as it once was. I can't even move my taskbar to the side in windows 11 without installing a third-party program to patch explorer.
> Isn't it unfortunate, the absolute degree everything legacy is at least in some way tethered to windows. If only there had been an open alternative, it would allow huge communities to emerge keeping very old software/games working indefinitely.
Every time I've tried it, from 2007 to now, it's been a buggy hunk of crap. I normally try not to disparage peoples software projects, but I really don't get ReactOS. I tried it again actually just a few weeks ago. It's barely usable. You'll have far fewer problems just using Wine with Linux.
That can already be done with Proton for anyone who wants to. But few, if any, are going to step up for the more obscure games. Relying on the benevolence of volunteers is never going to work in the long run either.
It's just ridiculous. Windows 11 currently has this bug where the file explorer just freezes all the time. Everyone is experiencing it at work. I cannot believe how a core product gets away with this.
Every time I've investigated an issue like this, it was something outside of explorer. Most of the time some kind of plugin that I didn't want (PDF readers, Tortoise SVN/Git, document preview handlers, you name it), mapped network drives not responding, or file system corruption that went by seemingly unnoticed.
At some point I started Autoruns and just disabled every DLL that didn't come from Microsoft and that I didn't strictly need. It sped up Windows immensely, and I went back enabling maybe one or two of those DLLs at a later point because it broke functionality.
I could've saved weeks of my life if Microsoft had just added a little popup that says "7zip.dll is adding 24% extra time to opening right click menus, disable it Y/N" every time a badly programmed plugin slowed down my shell.
A tale as old as time. It always seemed wild to me File Explorer is allowed to have so much synchronously driven activity. Like sure, display a loading symbol in the content area if I open a network share that's not already mounted (or whatever else it may wait on)... but don't lock the whole darn window so closing it becomes unresponsive!
Process Monitor is invaluable for investigating cases like that - at least one can look at what Windows is actually doing at that moment of freezing:
>Process Monitor is an advanced monitoring tool for Windows that shows real-time file system, Registry and process/thread activity. It combines the features of two legacy Sysinternals utilities, Filemon and Regmon ...
It's usually because there's some non-local stuff on your sidebar that it's trying to load - either a pinned item or a recently opened / frequently opened thing that's on network storage.
It's stupid but Windows has choked on that situation for many years.
Since I'm not seeing issues like this I'm assuming these are computers on an active directory... I remember XP having a few fun issues like this when a GPO refreshed links to a file that didn't exist and froze for a moment trying to resolve them.
I havent experienced that one myself, but I have other problems with the win 11 explorer. Like how when using the keyboard to navigate the right click menu, you cant just navigate into a submenu, but have to navigatw up or down after navigating into it, then the other way, to select the topmost item. And thats one thing I encounter many times a day at work.
That can happen if you have a mapped network drive which isn't immediately responding or which is offline. If you hover over the drive in Explorer (even accidentally) it will immediately try to query the network location. This can cause massive delay.
It's really stark when you compare it to something like a linux desktop running KDE or Gnome. Both pretty full featured desktops that were built for the computers I used as a kid.
While there's been a bit of polish, the two simply sip hardware requirements. So much so that you can put them on things like a raspberry pi 3 and still get a decent experience.
It's really funny to me as well. All this effort put into low level performance seems like picking up pennies in front of a steamroller. The operating system (and core business software such as Office) is overflowing with bloat that absolutely tanks the performance and responsiveness of the system. On a fresh boot I might as well go for a 15 minute coffee break lest I end up with multiple hung applications blocked on the UI thread.
It's so bad that Microsoft is actually going to start preloading Office on boot to speed up the application start times.
It was quite the shock to me recently when I had to use a Surface Laptop (the ARM one). Snapdragon X Elite & 32GB of RAM and took almost double the time to get to the desktop from a cold start compared to my M2 Air. Then even once everything was loaded, interacting with the system just did not feel responsive at all, the most egregious being file explorer and the right click menu.
And I have my own gripes with macOS feeling like it's slow due to the animations and me wanting to move faster than it can. Windows used to happily oblige, but now it's laggy.
Microsoft is too caught up in shoving Copilot everywhere to care though.
It's bad everywhere. Every time I've upgraded Ubuntu on my old laptop, performance gets worse and worse because more and more junk keeps getting added. Absolutely maddening.
They gave the different sorts of locks different names. Locks usable across processes are mutexes, and locks only usable within a process are critical sections.
Different names can be a huge source of confusion. The C++ standard library uses `std::mutex` as a lightweight synchronization lock. But on Win32, `Mutex` refers to a heavy kind of lock that can be used across processes. Very different things despite both using the same word "mutex" in the name.
Here's another example of confusing terminology. In the C standard library, `fflush` just advances you to the next step, where your buffer goes out to the 'write file' system call, where your data sits in the disk cache to be written later on. Meanwhile, Win32's `FlushFileBuffers` actually forces everything out to the disk, acting much more like `fsync`. Yet again, very different things despite using the same word "flush" in the name.
To add to what others have said, additional characteristics of a Win32 critical section:
- It is purely an in-process lock, and originally the main way of arbitrating access to shared memory within a process.
- It is counted and can be recursively locked.
- It defaults to simple blocking, but can also be configured to do some amount of spin-waiting before blocking.
- CritSecs are registered in a global debug list that can be accessed by debuggers. WinDbg's !locks command can display all locked critical sections in a process and which threads have locked them.
Originally in Win32, there were only two types of lock, the critical section for in-process locking, and the mutex for cross-process or named locks. Vista added the slim reader/writer lock, which is a much lighter weight, pointer-sized lock that uses the more modern wait-on-address approach to locking.
A critical section is code that accesses mutable shared data in a non-atomic way (i.e. as several steps, the classic example is: fetch data into a register, process that data, store the result back into memory). A lock is a mechanism that protects such data by preventing other code (or other threads running the same code) from accessing that data until the critical section completes.
Locks come in several types. A developer picks one type depending on the use of the protected data; for example, exclusive, reader-writer, and others.
Locks are great at preventing data corruption and data loss, but come with issues. They can hurt performance, can cause "liveness" and other issues, and are usually "advisory" ("mandatory" locks which are enforced by the OS are rarely available) so developers must remember to protect data by using locks around every critical section.
Modern hardware includes support for many lock-free mechanisms that can greatly reduce the need for locks.
It's just a lock. It's analogous to a pthread_mutex_t (which on Linux is a futex), where the operation in the uncontended case is a single atomic access to shared memory. The contended case needs to enter the kernel to suspend, or to make a decision about who to wake up, and that seems to be the subject of the blog post.
It's a kind of lock. Critsecs are faster and lighter weight than mutices (kinda like a futex), but cannot be shared between processes, only threads within a process. Mutices can be shared between processes but because of that they have to make syscalls every time they're locked or released.
In embedded (not sure how applicable here?) you invoke a critical section to access a lock. You will have an interrupt handler. Inside that, you will invoke a critical section, which prevents other processes from interrupting it. Inside the CS, you an get a handle to a mutex that has shared state. The mutex is what I would call the "lock" in this convention.
This is hands down the worst Old New Thing he ever wrote. He either is, or at least should be, ashamed of the poor engineering his colleagues are doing, and trying weakly to defend them.
Monkeying with critical sections is hard. Monkeying with them due to performance and memory optimization while maintaining correctness is incredibly hard. If they'd done a good job of it, no one would have noticed, and Raymond would have had a cool story to tell. Instead we got this.
But they did a good job of it? The change of behavior is San Andreas is due to an invalid memory access reading out of bounds into an area of the stack that was only coincidentally initialized by a previous iteration.
They didn't make any changes in correctness. The game itself is broken, and it's normal to undefined behavior from out of bounds accesses will change between OS versions, even just for security reasons. In fact, other versions of the game did fix this bug in a patch, it just didn't get picked because people go out of their way to downgrade the game in order to maintain some cut assets and features.
What? They did in fact maintain correctness. GTA was emphatically in the wrong here and only accidentally worked for a long time because of some internals of the CriticalSection code that they didn't even know they were depending on. The changes to that code didn't modify correctness. The issue was that GTA was relying on undefined behavior. GTA didn't know they had a bug because the undefined behavior happened to be in their favor for a long time. But it's a minor miracle that it hadn't broken before this in a myriad of other ways.
Rockstar actually did fix this bug some years ago, but because some content was removed, people instead downgrade to an earlier version that still has the bug and rely on community patches.
If they’d done a good job, they wouldn’t have made a change that used a little more stack space and triggered an old bug where GTA used an uninitialized local variable? Huh?
After a while that kool-aid, chilled to optimum temperature, on infinite tap, becomes an aqueous sanctuary, even the most staunch hold-outs cannot resist.
The solution seems to be installing and fully activating the operating system in the VM while it's still possible, then archiving the VM image. However, I don't know how reliable this method is, since the Windows OS may require reactivation if the hardware configuration changes significantly. Therefore, if the future VM host machine exposes slightly different hardware to the guest machine, the activation might be gone.
I agree in the general case, but this particular case isn’t a good argument for it.
You can't blame the user for the fact that the old software contains something that is, technically, an invalid use of the API, meaning the software shouldn't have worked, even in the past. The only way to reliably make the old software work as intended is to have an OS version from that time available.
You just invented "run in compatibility mode"
That's a completely backwards take though. Windows is practically the only platform in the world that cares about backwards compatibility. On Windows you can run a 20 year old executable and you've got pretty good chance it runs. With Linux operating systems you have no idea if something compiled on the last LTS release runs on the next one.
This is one of the few issues where having a private company control the entire stack and providing a stable ABI for decades is actually a benefit, to the point where your target if you want to build games on linux is...Win32 (https://blog.hiler.eu/win32-the-only-stable-abi/)
The title and discussion of the article is "Why is Windows still tinkering with critical sections." not "Why Windows is cast in stone."
The Linux community already stumbles at this and needs Windows to help it out. "Win32 is the only stable ABI on Linux" has been said so many times it isn't a joke any more. Keep in mind that the OS being open doesn't make the games open. Wine is possible because of Win32's die-hard commitment to long-term binary compatibility. I'm not so sure we're in a bad situation here. The Linux userspace has never had this degree of backwards binary compatibility. The kernel doesn't break userspace but userspace breaks itself all the time.
Linux userspace gets lots of other benefits from this rapid-iteration approach that doesn't concern itself with literally decades of binary compatibility, but keeping old games running indefinitely isn't one of them.
Running Linux on regular consumer hardware in 2005 was not really any harder than it is today. In fact, many of the same problems still exist! GPU drivers and janky wifi and power-saving modes, same shit, different decade.
There's Steam Deck now, and Android, but those are still quite proprietary driven by single companies, so I'm not really sure they fit what you mean about an open alternative.
I've been using Linux only as a desktop for 30 years, so that's a strange comment. For sure games and other software that was written to run on Windows exclusively, ran best on Windows (who could have predicted it!). But as a desktop, Linux has been usable for many decades.
Windows is actually excellent at maintain backwards compatibility. A program written 30 years ago probably still works today.
Rather: Windows is actually excellent at maintain backwards compatibility for binary programs.
There exist lots of other backwards-compatibility topics like
- being backwards-compatible in the user interface (in a business setting, ensuring that the business-critical applications still run is a problem of the IT, but if the user interface changes, people will complain. I just say "Windows 8" or "Office ribbons" (when they were introduced)). I would for example claim that very specifically for the shell interface, the GNU/Linux crowd cares a lot more about user-interface backwards compatibility than what Microsoft does.
- being backwards-compatible in the hardware requirements (i.e. "will it still run on an old computer"). I just want to mention the drama around Windows 11 because it doesn't run on still actively used hardware so that Microsoft cannot force the update on all Windows 10 users, but on the other hand wants to terminate the support for Windows 10.
Have a look at ReactOS:
> https://reactos.org/
> https://en.wikipedia.org/wiki/ReactOS
Every time I've tried it, from 2007 to now, it's been a buggy hunk of crap. I normally try not to disparage peoples software projects, but I really don't get ReactOS. I tried it again actually just a few weeks ago. It's barely usable. You'll have far fewer problems just using Wine with Linux.
At some point I started Autoruns and just disabled every DLL that didn't come from Microsoft and that I didn't strictly need. It sped up Windows immensely, and I went back enabling maybe one or two of those DLLs at a later point because it broke functionality.
I could've saved weeks of my life if Microsoft had just added a little popup that says "7zip.dll is adding 24% extra time to opening right click menus, disable it Y/N" every time a badly programmed plugin slowed down my shell.
>Process Monitor is an advanced monitoring tool for Windows that shows real-time file system, Registry and process/thread activity. It combines the features of two legacy Sysinternals utilities, Filemon and Regmon ...
https://learn.microsoft.com/en-us/sysinternals/downloads/pro...
It's stupid but Windows has choked on that situation for many years.
Probably all you can do is keep poking your IT support and hope it goes up the line until someone finds or creates the fix/workaround.
While there's been a bit of polish, the two simply sip hardware requirements. So much so that you can put them on things like a raspberry pi 3 and still get a decent experience.
It was quite the shock to me recently when I had to use a Surface Laptop (the ARM one). Snapdragon X Elite & 32GB of RAM and took almost double the time to get to the desktop from a cold start compared to my M2 Air. Then even once everything was loaded, interacting with the system just did not feel responsive at all, the most egregious being file explorer and the right click menu.
And I have my own gripes with macOS feeling like it's slow due to the animations and me wanting to move faster than it can. Windows used to happily oblige, but now it's laggy.
Microsoft is too caught up in shoving Copilot everywhere to care though.
https://news.ycombinator.com/item?id=43772311
Here's another example of confusing terminology. In the C standard library, `fflush` just advances you to the next step, where your buffer goes out to the 'write file' system call, where your data sits in the disk cache to be written later on. Meanwhile, Win32's `FlushFileBuffers` actually forces everything out to the disk, acting much more like `fsync`. Yet again, very different things despite using the same word "flush" in the name.
- It is purely an in-process lock, and originally the main way of arbitrating access to shared memory within a process.
- It is counted and can be recursively locked.
- It defaults to simple blocking, but can also be configured to do some amount of spin-waiting before blocking.
- CritSecs are registered in a global debug list that can be accessed by debuggers. WinDbg's !locks command can display all locked critical sections in a process and which threads have locked them.
Originally in Win32, there were only two types of lock, the critical section for in-process locking, and the mutex for cross-process or named locks. Vista added the slim reader/writer lock, which is a much lighter weight, pointer-sized lock that uses the more modern wait-on-address approach to locking.
Locks come in several types. A developer picks one type depending on the use of the protected data; for example, exclusive, reader-writer, and others.
Locks are great at preventing data corruption and data loss, but come with issues. They can hurt performance, can cause "liveness" and other issues, and are usually "advisory" ("mandatory" locks which are enforced by the OS are rarely available) so developers must remember to protect data by using locks around every critical section.
Modern hardware includes support for many lock-free mechanisms that can greatly reduce the need for locks.
Today you can use SRWLock or WaitOnAddress on Windows(or std::shared_mutex for portable impl, but not std::mutex because reasons).
Monkeying with critical sections is hard. Monkeying with them due to performance and memory optimization while maintaining correctness is incredibly hard. If they'd done a good job of it, no one would have noticed, and Raymond would have had a cool story to tell. Instead we got this.
Sigh, Microsoft, what's happening over there?
They didn't make any changes in correctness. The game itself is broken, and it's normal to undefined behavior from out of bounds accesses will change between OS versions, even just for security reasons. In fact, other versions of the game did fix this bug in a patch, it just didn't get picked because people go out of their way to downgrade the game in order to maintain some cut assets and features.
Using extra stack space has got to be on a list of things likely to cause trouble.