python: patch semaphore.c to fix pid namespace bug
Currently python2.7 tries to create semaphores as a file like
"/dev/shm/mp<pid>-<counter>". This assumes that there is only one
process per pid, which is not the case with pid namespacing which is
used to run builds in parallel.
The fix is to add another suffix, the current time's microseconds, which
should very likely be unique. Furthermore, we retry up to 100 times
until there is no collision.
The change to dev-install is necessary because of crbug.com/489895.
BUG=chromium:481223
TEST=No more of Python's unit tests failed; a sqlite3 test was broken.
Change-Id: Ib80f2b9d26d6c7309372742bbd16ffd28cb56e25
Reviewed-on: https://chromium-review.googlesource.com/271417
Reviewed-by: David James <davidjames@chromium.org>
Tested-by: Paul Hobbs <phobbs@google.com>
Reviewed-by: Mike Frysinger <vapier@chromium.org>
Commit-Queue: Mike Frysinger <vapier@chromium.org>
diff --git a/dev-lang/python/files/python-2.7.3-unique-semaphore-name.patch b/dev-lang/python/files/python-2.7.3-unique-semaphore-name.patch
new file mode 100644
index 0000000..d2c4e53
--- /dev/null
+++ b/dev-lang/python/files/python-2.7.3-unique-semaphore-name.patch
@@ -0,0 +1,55 @@
+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;