blob: d2c4e5308ffd05d991908bec979bdefbd3ef36bb [file] [log] [blame]
Paul Hobbs43d07e62015-05-14 16:43:16 -07001With pid namespaces, we may have multiple processes with the same pid.
2Instead of relying on the pid to be unique, we use the microseconds time
3to attempt to a unique filename.
4
5This patch is inspired by the following (large) patch to Python 3.4, which
6solves 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;