From 4ecc7bd3fce0642d6ffe6655a5b39cb0212efa49 Mon Sep 17 00:00:00 2001 From: David CARLIER Date: Sun, 16 Jan 2022 13:48:52 +0000 Subject: [PATCH 1/4] posixshmem module shm_rename freebsd support. --- .../_multiprocessing/clinic/posixshmem.c.h | 71 ++++++++++++++++++- Modules/_multiprocessing/posixshmem.c | 49 +++++++++++++ Modules/posixmodule.c | 10 +++ configure | 3 +- configure.ac | 2 +- pyconfig.h.in | 3 + 6 files changed, 134 insertions(+), 4 deletions(-) diff --git a/Modules/_multiprocessing/clinic/posixshmem.c.h b/Modules/_multiprocessing/clinic/posixshmem.c.h index 1b894ea4c67adc..da9436873053b4 100644 --- a/Modules/_multiprocessing/clinic/posixshmem.c.h +++ b/Modules/_multiprocessing/clinic/posixshmem.c.h @@ -42,6 +42,71 @@ _posixshmem_shm_open(PyObject *module, PyObject *args, PyObject *kwargs) #endif /* defined(HAVE_SHM_OPEN) */ +#if defined(HAVE_SHM_RENAME) + +PyDoc_STRVAR(_posixshmem_shm_rename__doc__, +"shm_rename($module, /, path_from, path_to, flags)\n" +"--\n" +"\n" +"Rename a shared memory object.\n" +"\n" +"Remove a shared memory object and relink to another path\n" +"By default, if the destination path already exist, it will be unlinked.\n" +"With the SHM_RENAME_EXCHANGE flag, source and destination paths\n" +"will be exchanged.\n" +"With the SHM_RENAME_NOREPLACE flag, an error will be triggered\n" +"if the destination alredady exists."); + +#define _POSIXSHMEM_SHM_RENAME_METHODDEF \ + {"shm_rename", (PyCFunction)(void(*)(void))_posixshmem_shm_rename, METH_FASTCALL|METH_KEYWORDS, _posixshmem_shm_rename__doc__}, + +static PyObject * +_posixshmem_shm_rename_impl(PyObject *module, PyObject *path_from, + PyObject *path_to, int flags); + +static PyObject * +_posixshmem_shm_rename(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + static const char * const _keywords[] = {"path_from", "path_to", "flags", NULL}; + static _PyArg_Parser _parser = {NULL, _keywords, "shm_rename", 0}; + PyObject *argsbuf[3]; + PyObject *path_from; + PyObject *path_to; + int flags; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 3, 3, 0, argsbuf); + if (!args) { + goto exit; + } + if (!PyUnicode_Check(args[0])) { + _PyArg_BadArgument("shm_rename", "argument 'path_from'", "str", args[0]); + goto exit; + } + if (PyUnicode_READY(args[0]) == -1) { + goto exit; + } + path_from = args[0]; + if (!PyUnicode_Check(args[1])) { + _PyArg_BadArgument("shm_rename", "argument 'path_to'", "str", args[1]); + goto exit; + } + if (PyUnicode_READY(args[1]) == -1) { + goto exit; + } + path_to = args[1]; + flags = _PyLong_AsInt(args[2]); + if (flags == -1 && PyErr_Occurred()) { + goto exit; + } + return_value = _posixshmem_shm_rename_impl(module, path_from, path_to, flags); + +exit: + return return_value; +} + +#endif /* defined(HAVE_SHM_RENAME) */ + #if defined(HAVE_SHM_UNLINK) PyDoc_STRVAR(_posixshmem_shm_unlink__doc__, @@ -82,7 +147,11 @@ _posixshmem_shm_unlink(PyObject *module, PyObject *args, PyObject *kwargs) #define _POSIXSHMEM_SHM_OPEN_METHODDEF #endif /* !defined(_POSIXSHMEM_SHM_OPEN_METHODDEF) */ +#ifndef _POSIXSHMEM_SHM_RENAME_METHODDEF + #define _POSIXSHMEM_SHM_RENAME_METHODDEF +#endif /* !defined(_POSIXSHMEM_SHM_RENAME_METHODDEF) */ + #ifndef _POSIXSHMEM_SHM_UNLINK_METHODDEF #define _POSIXSHMEM_SHM_UNLINK_METHODDEF #endif /* !defined(_POSIXSHMEM_SHM_UNLINK_METHODDEF) */ -/*[clinic end generated code: output=be0661dbed83ea23 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=dedbfe53c5c203af input=a9049054013a1b77]*/ diff --git a/Modules/_multiprocessing/posixshmem.c b/Modules/_multiprocessing/posixshmem.c index 425ce10075c156..65110d5de4262c 100644 --- a/Modules/_multiprocessing/posixshmem.c +++ b/Modules/_multiprocessing/posixshmem.c @@ -68,6 +68,52 @@ _posixshmem_shm_open_impl(PyObject *module, PyObject *path, int flags, } #endif /* HAVE_SHM_OPEN */ +#ifdef HAVE_SHM_RENAME +/*[clinic input] +_posixshmem.shm_rename + path_from: unicode + path_to: unicode + flags: int + +Rename a shared memory object. + +Remove a shared memory object and relink to another path +By default, if the destination path already exist, it will be unlinked. +With the SHM_RENAME_EXCHANGE flag, source and destination paths +will be exchanged. +With the SHM_RENAME_NOREPLACE flag, an error will be triggered +if the destination alredady exists. + +[clinic start generated code]*/ + +static PyObject * +_posixshmem_shm_rename_impl(PyObject *module, PyObject *path_from, + PyObject *path_to, int flags) +/*[clinic end generated code: output=a9101f606826ad30 input=e32a44cee3e0326e]*/ +{ + int rv; + int async_err = 0; + const char *from = PyUnicode_AsUTF8(path_from); + const char *to = PyUnicode_AsUTF8(path_to); + if (from == NULL || to == NULL) { + return NULL; + } + do { + Py_BEGIN_ALLOW_THREADS + rv = shm_rename(from, to, flags); + Py_END_ALLOW_THREADS + } while (rv < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); + + if (rv < 0) { + if (!async_err) + PyErr_SetFromErrnoWithFilenameObjects(PyExc_OSError, path_from, path_to); + return NULL; + } + + Py_RETURN_NONE; +} +#endif /* HAVE_SHM_RENAME */ + #ifdef HAVE_SHM_UNLINK /*[clinic input] _posixshmem.shm_unlink @@ -111,6 +157,9 @@ _posixshmem_shm_unlink_impl(PyObject *module, PyObject *path) static PyMethodDef module_methods[ ] = { _POSIXSHMEM_SHM_OPEN_METHODDEF +#if defined(HAVE_SHM_RENAME) + _POSIXSHMEM_SHM_RENAME_METHODDEF +#endif _POSIXSHMEM_SHM_UNLINK_METHODDEF {NULL} /* Sentinel */ }; diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index fd70b38bddec79..a3d43316fb90c9 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -17288,6 +17288,16 @@ all_ins(PyObject *m) #endif #endif /* HAVE_MEMFD_CREATE */ +#ifdef HAVE_SHM_RENAME +#ifdef SHM_RENAME_EXCHANGE + if (PyModule_AddIntMacro(m, SHM_RENAME_EXCHANGE)) return -1; +#endif +#ifdef SHM_RENAME_NOREPLACE + if (PyModule_AddIntMacro(m, SHM_RENAME_NOREPLACE)) return -1; +#endif +#endif /* HAVE_SHM_RENAME */ + +#ifdef HAVE_EVENTFD #if defined(HAVE_EVENTFD) && defined(EFD_CLOEXEC) if (PyModule_AddIntMacro(m, EFD_CLOEXEC)) return -1; #ifdef EFD_NONBLOCK diff --git a/configure b/configure index fcf34f050861be..09298bc16bebb1 100755 --- a/configure +++ b/configure @@ -27375,8 +27375,7 @@ fi # endif #endif " - - for ac_func in shm_open shm_unlink + for ac_func in shm_open shm_rename shm_unlink do : as_ac_var=`printf "%s\n" "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" diff --git a/configure.ac b/configure.ac index f6df9b8bb41cc9..af9d625a7c0ef2 100644 --- a/configure.ac +++ b/configure.ac @@ -6873,7 +6873,7 @@ WITH_SAVE_ENV([ # endif #endif " - AC_CHECK_FUNCS([shm_open shm_unlink], [have_posix_shmem=yes], [have_posix_shmem=no]) + AC_CHECK_FUNCS([shm_open shm_rename shm_unlink], [have_posix_shmem=yes], [have_posix_shmem=no]) _RESTORE_VAR([ac_includes_default]) ]) diff --git a/pyconfig.h.in b/pyconfig.h.in index 63a3437ebb3eac..5e26d4206602e7 100644 --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -1138,6 +1138,9 @@ /* Define to 1 if you have the `shm_open' function. */ #undef HAVE_SHM_OPEN +/* Define to 1 if you have the `shm_rename' function. */ +#undef HAVE_SHM_RENAME + /* Define to 1 if you have the `shm_unlink' function. */ #undef HAVE_SHM_UNLINK From 1336f8c8cd257f21f59acc41f57ec004b4bd583b Mon Sep 17 00:00:00 2001 From: David CARLIER Date: Sun, 16 Jan 2022 16:31:47 +0000 Subject: [PATCH 2/4] update shared_memory library --- Lib/multiprocessing/shared_memory.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/Lib/multiprocessing/shared_memory.py b/Lib/multiprocessing/shared_memory.py index 67e70fdc27cf31..e29090422508c3 100644 --- a/Lib/multiprocessing/shared_memory.py +++ b/Lib/multiprocessing/shared_memory.py @@ -11,6 +11,7 @@ from functools import partial import mmap import os +import platform import errno import struct import secrets @@ -253,6 +254,32 @@ def unlink(self): if self._track: resource_tracker.unregister(self._name, "shared_memory") + def rename(self, newname, flags = 0): + """Renames a shared memory block. + + The policy how the operation is handled depends on the flag passed. + The default behavior is if the newname already exists, it will + be unlinked beforehand. + With the SHM_RENAME_EXCHANGE flag, the old and new name will + be exchanged. + With the SHM_RENAME_NOREPLACE flag, an error will be returned + if the new name exists. + """ + if platform.system() != "FreeBSD": + raise OSError("Unsupported operation on this platform") + + if newname: + newname = "/" + newname if self._prepend_leading_slash else newname + r = _posixshmem.shm_rename(self._name, newname, flags) + if r == None: + from .resource_tracker import unregister, register + unregister(self._name, "shared_memory") + self._name = newname + register(self._name, "shared_memory") + return True + + return False + _encoding = "utf8" From d11ff820ad728c00aefd9133d1f30afa05365b80 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Sun, 16 Jan 2022 20:29:03 +0000 Subject: [PATCH 3/4] doc update --- Doc/library/multiprocessing.shared_memory.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Doc/library/multiprocessing.shared_memory.rst b/Doc/library/multiprocessing.shared_memory.rst index 933fd07d62418a..fcc860c243b8c0 100644 --- a/Doc/library/multiprocessing.shared_memory.rst +++ b/Doc/library/multiprocessing.shared_memory.rst @@ -112,6 +112,15 @@ copying of data. This method has no effect on Windows, where the only way to delete a shared memory block is to close all handles. + .. method:: rename(newname, flags) + + Renames the underlying shared memory block to ``newname``. By + default, if ``newname`` already exists, it will be unlinked + beforehand. Passing the ``os.SHM_RENAME_EXCHANGE`` as ``flags``, + an exchange with ``newname`` will be proceeded instead. Passing + the ``os.SHM_RENAME_NOREPLACE`` as ``flags``, an error + will be triggered if ``newname`` already exists. + .. attribute:: buf A memoryview of contents of the shared memory block. From 13734b63a3f38fc4cf79a92e2503f20eee3c6fef Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Mon, 17 Jan 2022 20:03:58 +0000 Subject: [PATCH 4/4] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Lib/multiprocessing/shared_memory.py | 13 ++--- .../2022-01-17-20-03-56.bpo-46398.FATeqM.rst | 1 + .../_multiprocessing/clinic/posixshmem.c.h | 47 +++++-------------- Modules/_multiprocessing/posixshmem.c | 17 +++---- Modules/posixmodule.c | 1 - 5 files changed, 27 insertions(+), 52 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2022-01-17-20-03-56.bpo-46398.FATeqM.rst diff --git a/Lib/multiprocessing/shared_memory.py b/Lib/multiprocessing/shared_memory.py index e29090422508c3..ccb8b4da508fe3 100644 --- a/Lib/multiprocessing/shared_memory.py +++ b/Lib/multiprocessing/shared_memory.py @@ -265,19 +265,14 @@ def rename(self, newname, flags = 0): With the SHM_RENAME_NOREPLACE flag, an error will be returned if the new name exists. """ - if platform.system() != "FreeBSD": + if !platform.hasattr("shm_rename"): raise OSError("Unsupported operation on this platform") if newname: newname = "/" + newname if self._prepend_leading_slash else newname - r = _posixshmem.shm_rename(self._name, newname, flags) - if r == None: - from .resource_tracker import unregister, register - unregister(self._name, "shared_memory") - self._name = newname - register(self._name, "shared_memory") - return True - + self._fd = _posixshmem.shm_rename(self._name, newname, flags) + self._name = newname + return True return False diff --git a/Misc/NEWS.d/next/Library/2022-01-17-20-03-56.bpo-46398.FATeqM.rst b/Misc/NEWS.d/next/Library/2022-01-17-20-03-56.bpo-46398.FATeqM.rst new file mode 100644 index 00000000000000..b0c968e1637e79 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-01-17-20-03-56.bpo-46398.FATeqM.rst @@ -0,0 +1 @@ +Add :method:`rename` to the `multiprocessing.shared_memory` library for FreeBSD. \ No newline at end of file diff --git a/Modules/_multiprocessing/clinic/posixshmem.c.h b/Modules/_multiprocessing/clinic/posixshmem.c.h index da9436873053b4..1451f9d902dbba 100644 --- a/Modules/_multiprocessing/clinic/posixshmem.c.h +++ b/Modules/_multiprocessing/clinic/posixshmem.c.h @@ -45,12 +45,12 @@ _posixshmem_shm_open(PyObject *module, PyObject *args, PyObject *kwargs) #if defined(HAVE_SHM_RENAME) PyDoc_STRVAR(_posixshmem_shm_rename__doc__, -"shm_rename($module, /, path_from, path_to, flags)\n" +"shm_rename($module, path_from, path_to, flags, /)\n" "--\n" "\n" "Rename a shared memory object.\n" "\n" -"Remove a shared memory object and relink to another path\n" +"Remove a shared memory object and relink to another path.\n" "By default, if the destination path already exist, it will be unlinked.\n" "With the SHM_RENAME_EXCHANGE flag, source and destination paths\n" "will be exchanged.\n" @@ -58,48 +58,30 @@ PyDoc_STRVAR(_posixshmem_shm_rename__doc__, "if the destination alredady exists."); #define _POSIXSHMEM_SHM_RENAME_METHODDEF \ - {"shm_rename", (PyCFunction)(void(*)(void))_posixshmem_shm_rename, METH_FASTCALL|METH_KEYWORDS, _posixshmem_shm_rename__doc__}, + {"shm_rename", (PyCFunction)(void(*)(void))_posixshmem_shm_rename, METH_FASTCALL, _posixshmem_shm_rename__doc__}, -static PyObject * +static int _posixshmem_shm_rename_impl(PyObject *module, PyObject *path_from, PyObject *path_to, int flags); static PyObject * -_posixshmem_shm_rename(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +_posixshmem_shm_rename(PyObject *module, PyObject *args, PyObject *kwargs) { PyObject *return_value = NULL; - static const char * const _keywords[] = {"path_from", "path_to", "flags", NULL}; - static _PyArg_Parser _parser = {NULL, _keywords, "shm_rename", 0}; - PyObject *argsbuf[3]; + static char *_keywords[] = {"path_from", "path_to", "flags", NULL}; PyObject *path_from; PyObject *path_to; int flags; + int _return_value; - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 3, 3, 0, argsbuf); - if (!args) { - goto exit; - } - if (!PyUnicode_Check(args[0])) { - _PyArg_BadArgument("shm_rename", "argument 'path_from'", "str", args[0]); - goto exit; - } - if (PyUnicode_READY(args[0]) == -1) { - goto exit; - } - path_from = args[0]; - if (!PyUnicode_Check(args[1])) { - _PyArg_BadArgument("shm_rename", "argument 'path_to'", "str", args[1]); - goto exit; - } - if (PyUnicode_READY(args[1]) == -1) { + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Ui|i:shm_rename", _keywords, + &path_from, &path_to, &flags)) goto exit; - } - path_to = args[1]; - flags = _PyLong_AsInt(args[2]); - if (flags == -1 && PyErr_Occurred()) { + _return_value = _posixshmem_shm_rename_impl(module, path_from, path_to, flags); + if ((_return_value == -1) && PyErr_Occurred()) { goto exit; } - return_value = _posixshmem_shm_rename_impl(module, path_from, path_to, flags); + return_value = PyLong_FromLong((long)_return_value); exit: return return_value; @@ -122,9 +104,6 @@ PyDoc_STRVAR(_posixshmem_shm_unlink__doc__, #define _POSIXSHMEM_SHM_UNLINK_METHODDEF \ {"shm_unlink", (PyCFunction)(void(*)(void))_posixshmem_shm_unlink, METH_VARARGS|METH_KEYWORDS, _posixshmem_shm_unlink__doc__}, -static PyObject * -_posixshmem_shm_unlink_impl(PyObject *module, PyObject *path); - static PyObject * _posixshmem_shm_unlink(PyObject *module, PyObject *args, PyObject *kwargs) { @@ -154,4 +133,4 @@ _posixshmem_shm_unlink(PyObject *module, PyObject *args, PyObject *kwargs) #ifndef _POSIXSHMEM_SHM_UNLINK_METHODDEF #define _POSIXSHMEM_SHM_UNLINK_METHODDEF #endif /* !defined(_POSIXSHMEM_SHM_UNLINK_METHODDEF) */ -/*[clinic end generated code: output=dedbfe53c5c203af input=a9049054013a1b77]*/ +/*[clinic end generated code: output=ca3677d5d1e7755f input=a9049054013a1b77]*/ diff --git a/Modules/_multiprocessing/posixshmem.c b/Modules/_multiprocessing/posixshmem.c index 65110d5de4262c..fe38dcf16973f4 100644 --- a/Modules/_multiprocessing/posixshmem.c +++ b/Modules/_multiprocessing/posixshmem.c @@ -74,10 +74,11 @@ _posixshmem.shm_rename path_from: unicode path_to: unicode flags: int + / Rename a shared memory object. -Remove a shared memory object and relink to another path +Remove a shared memory object and relink to another path. By default, if the destination path already exist, it will be unlinked. With the SHM_RENAME_EXCHANGE flag, source and destination paths will be exchanged. @@ -86,17 +87,17 @@ if the destination alredady exists. [clinic start generated code]*/ -static PyObject * +static int _posixshmem_shm_rename_impl(PyObject *module, PyObject *path_from, PyObject *path_to, int flags) -/*[clinic end generated code: output=a9101f606826ad30 input=e32a44cee3e0326e]*/ +/*[clinic end generated code: output=a9101f606826ad30 input=0373bfc9c491e123]*/ { int rv; int async_err = 0; - const char *from = PyUnicode_AsUTF8(path_from); - const char *to = PyUnicode_AsUTF8(path_to); + const char *from = PyUnicode_AsUTF8AndSize(path_from, NULL); + const char *to = PyUnicode_AsUTF8AndSize(path_to, NULL); if (from == NULL || to == NULL) { - return NULL; + return -1; } do { Py_BEGIN_ALLOW_THREADS @@ -107,10 +108,10 @@ _posixshmem_shm_rename_impl(PyObject *module, PyObject *path_from, if (rv < 0) { if (!async_err) PyErr_SetFromErrnoWithFilenameObjects(PyExc_OSError, path_from, path_to); - return NULL; + return -1; } - Py_RETURN_NONE; + return rv; } #endif /* HAVE_SHM_RENAME */ diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index a3d43316fb90c9..0150a0d2cdb446 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -17297,7 +17297,6 @@ all_ins(PyObject *m) #endif #endif /* HAVE_SHM_RENAME */ -#ifdef HAVE_EVENTFD #if defined(HAVE_EVENTFD) && defined(EFD_CLOEXEC) if (PyModule_AddIntMacro(m, EFD_CLOEXEC)) return -1; #ifdef EFD_NONBLOCK