Paul Hobbs | 43d07e6 | 2015-05-14 16:43:16 -0700 | [diff] [blame] | 1 | With pid namespaces, we may have multiple processes with the same pid. |
| 2 | Instead of relying on the pid to be unique, we use the microseconds time |
| 3 | to attempt to a unique filename. |
| 4 | |
| 5 | This patch is inspired by the following (large) patch to Python 3.4, which |
| 6 | solves this bug incidentally during a refactoring: |
| 7 | https://bugs.python.org/issue8713 |
| 8 | |
| 9 | --- a/Modules/_multiprocessing/semaphore.c |
| 10 | +++ b/Modules/_multiprocessing/semaphore.c |
| 11 | @@ -7,6 +7,7 @@ |
| 12 | */ |
| 13 | |
| 14 | #include "multiprocessing.h" |
| 15 | +#include <time.h> |
| 16 | |
| 17 | enum { RECURSIVE_MUTEX, SEMAPHORE }; |
| 18 | |
| 19 | @@ -419,7 +420,7 @@ semlock_new(PyTypeObject *type, PyObject *args, PyObject *kwds) |
| 20 | { |
| 21 | char buffer[256]; |
| 22 | SEM_HANDLE handle = SEM_FAILED; |
| 23 | - int kind, maxvalue, value; |
| 24 | + int kind, maxvalue, value, try; |
| 25 | PyObject *result; |
| 26 | static char *kwlist[] = {"kind", "value", "maxvalue", NULL}; |
| 27 | static int counter = 0; |
| 28 | @@ -433,10 +434,24 @@ semlock_new(PyTypeObject *type, PyObject *args, PyObject *kwds) |
| 29 | return NULL; |
| 30 | } |
| 31 | |
| 32 | - PyOS_snprintf(buffer, sizeof(buffer), "/mp%ld-%d", (long)getpid(), counter++); |
| 33 | + /* With pid namespaces, we may have multiple processes with the same pid. |
| 34 | + * Instead of relying on the pid to be unique, we use the microseconds time |
| 35 | + * to attempt to a unique filename. */ |
| 36 | + for (try = 0; try < 100; ++try) { |
| 37 | + struct timespec tv; |
| 38 | + long arbitrary = clock_gettime(CLOCK_REALTIME, &tv) ? 0 : tv.tv_nsec; |
| 39 | + PyOS_snprintf(buffer, sizeof(buffer), "/mp%ld-%d-%ld", |
| 40 | + (long)getpid(), |
| 41 | + counter++, |
| 42 | + arbitrary); |
| 43 | + SEM_CLEAR_ERROR(); |
| 44 | + handle = SEM_CREATE(buffer, value, maxvalue); |
| 45 | + if (handle != SEM_FAILED) |
| 46 | + break; |
| 47 | + else if (errno != EEXIST) |
| 48 | + goto failure; |
| 49 | + } |
| 50 | |
| 51 | - SEM_CLEAR_ERROR(); |
| 52 | - handle = SEM_CREATE(buffer, value, maxvalue); |
| 53 | /* On Windows we should fail if GetLastError()==ERROR_ALREADY_EXISTS */ |
| 54 | if (handle == SEM_FAILED || SEM_GET_LAST_ERROR() != 0) |
| 55 | goto failure; |