| With pid namespaces, we may have multiple processes with the same pid. |
| Instead of relying on the pid to be unique, we use the microseconds time |
| to attempt to a unique filename. |
| |
| This patch is inspired by the following (large) patch to Python 3.4, which |
| solves this bug incidentally during a refactoring: |
| https://bugs.python.org/issue8713 |
| |
| --- a/Modules/_multiprocessing/semaphore.c |
| +++ b/Modules/_multiprocessing/semaphore.c |
| @@ -7,6 +7,7 @@ |
| */ |
| |
| #include "multiprocessing.h" |
| +#include <time.h> |
| |
| enum { RECURSIVE_MUTEX, SEMAPHORE }; |
| |
| @@ -419,7 +420,7 @@ semlock_new(PyTypeObject *type, PyObject *args, PyObject *kwds) |
| { |
| char buffer[256]; |
| SEM_HANDLE handle = SEM_FAILED; |
| - int kind, maxvalue, value; |
| + int kind, maxvalue, value, try; |
| PyObject *result; |
| static char *kwlist[] = {"kind", "value", "maxvalue", NULL}; |
| static int counter = 0; |
| @@ -433,10 +434,24 @@ semlock_new(PyTypeObject *type, PyObject *args, PyObject *kwds) |
| return NULL; |
| } |
| |
| - PyOS_snprintf(buffer, sizeof(buffer), "/mp%ld-%d", (long)getpid(), counter++); |
| + /* With pid namespaces, we may have multiple processes with the same pid. |
| + * Instead of relying on the pid to be unique, we use the microseconds time |
| + * to attempt to a unique filename. */ |
| + for (try = 0; try < 100; ++try) { |
| + struct timespec tv; |
| + long arbitrary = clock_gettime(CLOCK_REALTIME, &tv) ? 0 : tv.tv_nsec; |
| + PyOS_snprintf(buffer, sizeof(buffer), "/mp%ld-%d-%ld", |
| + (long)getpid(), |
| + counter++, |
| + arbitrary); |
| + SEM_CLEAR_ERROR(); |
| + handle = SEM_CREATE(buffer, value, maxvalue); |
| + if (handle != SEM_FAILED) |
| + break; |
| + else if (errno != EEXIST) |
| + goto failure; |
| + } |
| |
| - SEM_CLEAR_ERROR(); |
| - handle = SEM_CREATE(buffer, value, maxvalue); |
| /* On Windows we should fail if GetLastError()==ERROR_ALREADY_EXISTS */ |
| if (handle == SEM_FAILED || SEM_GET_LAST_ERROR() != 0) |
| goto failure; |