Last active
July 16, 2017 02:11
-
-
Save graphitemaster/3666b721be00e8285efb942c823afc7e to your computer and use it in GitHub Desktop.
nvbug work around data races atfork handlers
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* The following is an implementation of pthread_atfork that | |
| * does absolutely nothing when nvidia is being used for rendering. | |
| * | |
| * This is needed because nvidia adds atfork handlers which are not | |
| * async-signal safe and contain minor data-races which can lead to | |
| * unexpected crashes. | |
| * | |
| * For example from valgrind's helgrind | |
| * | |
| * ==17309== Possible data race during write of size 1 at 0x3EEEC5E0 by thread #27 | |
| * ==17309== Locks held: 2, at addresses 0x37F01248 0x4FAF8810 | |
| * ==17309== at 0x37C5494D: ??? (in /usr/lib/libGLX_nvidia.so.370.28) | |
| * ==17309== by 0xD4A61F5: fork (in /usr/lib/libc-2.24.so) | |
| * ==17309== by 0xD456CC0: _IO_proc_open@@GLIBC_2.2.5 (in /usr/lib/libc-2.24.so) | |
| * ==17309== by 0xD456FB7: popen@@GLIBC_2.2.5 (in /usr/lib/libc-2.24.so) | |
| * | |
| * The general technique involved here is to check /proc/$pid/maps | |
| * and see if there is an nvidia library loaded | |
| */ | |
| #define _GNU_SOURCE | |
| #include <sys/types.h> | |
| #include <sys/stat.h> | |
| #include <fcntl.h> | |
| #include <dlfcn.h> | |
| #include <pthread.h> | |
| #include <unistd.h> | |
| #include <limits.h> | |
| #include <stdio.h> | |
| #include <string.h> | |
| static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER; | |
| static pthread_once_t g_init = PTHREAD_ONCE_INIT; | |
| static int g_nvidia = 0; | |
| static int (*pthread_atfork_p)(void (*)(void), void (*)(void), void (*)(void)); | |
| static int (*__register_atfork_p)(void (*)(void), void(*)(void), void(*)(void), void*); | |
| static void init(void) { | |
| /* The true pthread_atfork and the LSB one*/ | |
| *(void **)&pthread_atfork_p = dlsym(RTLD_NEXT, "pthread_atfork"); | |
| *(void **)&__register_atfork_p = dlsym(RTLD_NEXT, "__register_atfork"); | |
| /* Check if we're running under nvidia */ | |
| char path[PATH_MAX], line[LINE_MAX]; | |
| pid_t pid = getpid(); | |
| sprintf(path, "/proc/%d/maps", (int)pid); | |
| int fd = open(path, O_RDONLY); | |
| while (read(fd, line, sizeof line) > 0) { | |
| static char nvidia[] = "nvidia"; | |
| if (!memmem(line, sizeof line, nvidia, sizeof nvidia)) continue; | |
| pthread_mutex_lock(&g_mutex); | |
| g_nvidia = 1; | |
| pthread_mutex_unlock(&g_mutex); | |
| break; | |
| } | |
| close(fd); | |
| } | |
| int __register_atfork(void (*prepare)(void), void (*parent)(void), void(*child)(void), void *dso) { | |
| pthread_once(&g_init, init); | |
| pthread_mutex_lock(&g_mutex); | |
| int status = g_nvidia ? -1 : __register_atfork_p(prepare, parent, child, dso); | |
| pthread_mutex_unlock(&g_mutex); | |
| return status; | |
| } | |
| int register_atfork(void (*prepare)(void), void (*parent)(void), void(*child)(void), void *dso) { | |
| return __register_atfork(prepare, parent, child, dso); | |
| } | |
| int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void)) { | |
| pthread_once(&g_init, init); | |
| pthread_mutex_lock(&g_mutex); | |
| int status = g_nvidia ? -1 : pthread_atfork_p(prepare, parent, child); | |
| pthread_mutex_unlock(&g_mutex); | |
| return status; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment