e1966ac26e
This has sat here for a long time pending careful review, because the logic is not easy to follow. Fortunately I think I understand it now. The described race is pretty much accurate. When a thread called RtlExitUserThread() in 1.7.38, it first decremented nb_threads. If it was the last thread, it would call exit() with the thread exit status; if not, it would mask off signals [the order here is important] and then call pthread_exit() with the status. When a thread called RtlExitUserProcess(), this happened: * The caller does a terminate_process() request to the server, which sends SIGQUIT to every thread *but* the caller. * The SIGQUIT handler calls terminate_thread() with a zero status. terminate_thread() masks off signals, then decrements nb_threads. If the aborting thread is the last thread, it would call _exit(), otherwise, it'd again just pthread_exit(). * Finally, the original thread would call exit(), with the intended status code. [All of the intermediate function calls and helpers are skipped for brevity and clarity]. The problem happens if both of these happen at the same time in different threads. In this case the RtlExitUserThread() thread could decrement nb_threads, then get interrupted by SIGQUIT and decrement nb_threads again. The end result is that, instead of the RtlExitUserProcess() thread exiting with the intended status, instead one of the SIGQUIT threads will be the "last" thread, and exit with the status that SIGQUIT uses, which is zero as described. A more serious race than this can be constructed if a thread is terminated by another thread while already exiting. In this case nb_threads would be executed twice, but the consequence would be that the *penultimate* thread to exit, later, would end up killing the process, since it thinks it's the ultimate thread. 2334f4e64582a518e4d5a7627472a0d817b147ef changed this. Now a thread calling RtlExitUserThread() does not decrement nb_threads, but instead asks the server if it's the last thread, and if so exit the whole process [at the time via exit(); later via RtlExitUserProcess().] If not the last thread, the threads mask off signals and then call pthread_exit() as before. This avoided the race, but added a different one, essentially the opposite problem: if two threads exit cleanly at the same time, neither one of them will think they're the last thread, then both will exit without calling exit(). Apparently (from IRC logs) this would leave the thread in a weird state where it'd still be running somehow, although it's not really clear how. In any case, this problem was fixed by fac1aabbef3753afc53a4ea4f933b3d0516fd302 upstream. Now if two threads call NtTerminateThread() on themselves at the same time, they really will exit cleanly and one will terminate the process. Critically, this is now safe from the original race, because decrementing nb_threads is done after masking off signals. |
||
---|---|---|
.github | ||
patches | ||
staging | ||
.gitignore | ||
LICENSE.md | ||
precommit-hook.sh | ||
README.md |
What is Wine Staging?
Wine Staging is the testing area of winehq.org. It contains bug fixes and features, which have not been integrated into the development branch yet. The idea of Wine Staging is to provide experimental features faster to end users and to give developers the possibility to discuss and improve their patches before they are integrated into the main branch. More information about Wine Staging can also be found on the WineHQ wiki.
Installation
Ready-to-use packages for Wine Staging are available for a variety of Linux distributions and for Mac OS X. Just follow the installation instructions for your operating system.
On most distributions the wine-staging
package is installed to
/opt/wine-staging
, such that multiple Wine versions can be installed in
parallel. If this is the case for your distribution, you will have to type
/opt/wine-staging/bin/wine
instead of just wine
. The same also applies for
other wine-specific programs like winecfg
. To learn more about how to use
Wine Staging, please take a look at the
usage instructions.
Building
Wine Staging is maintained as a set of patches which has to be applied on top of the development branch. In order to build Wine Staging, the first step is to setup a build environment for Wine, including all required dependencies. A lot of information about that is collected in the WineHQ Wiki.
In order to apply all Wine Staging patches it is recommended to use the
patchinstall.py
utility which takes care of applying all patches in the
correct order. For reference, the possible commandline arguments are:
Usage: ./staging/patchinstall.py [DESTDIR=path] [-W patchset] [patchset ...]
Autogenerated script to apply all Wine Staging patches on your Wine
source tree.
Configuration:
DESTDIR=path Specify the path to the wine source tree
--all Select all patches
--force-autoconf Run autoreconf and tools/make_requests after each patch
--help Display this help and exit
--no-autoconf Do not run autoreconf and tools/make_requests
--no-patchlist Do not apply patchlist (needed for 'wine --patches')
--upstream-commit Print the upstream Wine commit SHA1 and exit
--version Show version information and exit
-W patchset Exclude a specific patchset
Backends:
--backend=patch Use regular 'patch' utility to apply patches (default)
--backend=git-am Use 'git am' to apply patches
--backend=git-apply Use 'git apply' to apply patches
If you want to apply all patches with the patch
utility, the commandline
should look similar to this:
./staging/patchinstall.py DESTDIR="/path/to/wine" --all
Before you proceed with the compilation, please make sure that you installed all
additional build dependencies required for the Wine Staging features you are
interested in (check output of ./configure
). More information about building
Wine Staging, optional build dependencies, and hints for packagers are collected
in our Wiki.
Contributing
For information on contributing to Wine-Staging, please see https://wiki.winehq.org/Wine-Staging_Contributing. Note that GitHub pull requests are strongly dispreferred, especially for patches.
Donations
wine-staging is a large set of experimental patches which provide various improvements to WINE, but are not quite suitable for upstreaming. This set of patches has been continuously managed for many years by a small group of volunteers. The way this works is that we often review patches attached to various bug reports found at https://bugs.winehq.org/ which may fix bugs, but may not be quite suitable to be upstreamed due to needing some cleanup or more proper implementation. In the event that this happens, we add the patches to wine-staging instead, and keep them updated and maintained as well as attempt to clean them up to be upstreamed. We also both write and verify patches which fix various bugs that may not have patches, and in turn allow them run better using WINE. This includes testing on various hardware, games and applications.
Any expenses for applications, games, or hardware which we do not own comes out of pocket. In order to alleviate these expenses, we are now accepting donations. This in turn allows us to continue to perform testing, provide fixes, and get them upstreamed, ultimately aiming to provide a better experience for all WINE users. All of our work is provided publicly for free and can be found at https://gitlab.winehq.org/wine/wine-staging. We do not expect to be paid for any of the work provided, nor will donators receive any special benefits or compensation.
Donations are recieved through Patreon. Anyone interested may donate here: