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. diff --git a/Lib/multiprocessing/shared_memory.py b/Lib/multiprocessing/shared_memory.py index 67e70fdc27cf31..ccb8b4da508fe3 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,27 @@ 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.hasattr("shm_rename"): + raise OSError("Unsupported operation on this platform") + + if newname: + newname = "/" + newname if self._prepend_leading_slash else newname + self._fd = _posixshmem.shm_rename(self._name, newname, flags) + self._name = newname + return True + return False + _encoding = "utf8" 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 1b894ea4c67adc..1451f9d902dbba 100644 --- a/Modules/_multiprocessing/clinic/posixshmem.c.h +++ b/Modules/_multiprocessing/clinic/posixshmem.c.h @@ -42,6 +42,53 @@ _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, _posixshmem_shm_rename__doc__}, + +static int +_posixshmem_shm_rename_impl(PyObject *module, PyObject *path_from, + PyObject *path_to, int flags); + +static PyObject * +_posixshmem_shm_rename(PyObject *module, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + static char *_keywords[] = {"path_from", "path_to", "flags", NULL}; + PyObject *path_from; + PyObject *path_to; + int flags; + int _return_value; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Ui|i:shm_rename", _keywords, + &path_from, &path_to, &flags)) + goto exit; + _return_value = _posixshmem_shm_rename_impl(module, path_from, path_to, flags); + if ((_return_value == -1) && PyErr_Occurred()) { + goto exit; + } + return_value = PyLong_FromLong((long)_return_value); + +exit: + return return_value; +} + +#endif /* defined(HAVE_SHM_RENAME) */ + #if defined(HAVE_SHM_UNLINK) PyDoc_STRVAR(_posixshmem_shm_unlink__doc__, @@ -57,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) { @@ -82,7 +126,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=ca3677d5d1e7755f input=a9049054013a1b77]*/ diff --git a/Modules/_multiprocessing/posixshmem.c b/Modules/_multiprocessing/posixshmem.c index 425ce10075c156..fe38dcf16973f4 100644 --- a/Modules/_multiprocessing/posixshmem.c +++ b/Modules/_multiprocessing/posixshmem.c @@ -68,6 +68,53 @@ _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 int +_posixshmem_shm_rename_impl(PyObject *module, PyObject *path_from, + PyObject *path_to, int flags) +/*[clinic end generated code: output=a9101f606826ad30 input=0373bfc9c491e123]*/ +{ + int rv; + int async_err = 0; + const char *from = PyUnicode_AsUTF8AndSize(path_from, NULL); + const char *to = PyUnicode_AsUTF8AndSize(path_to, NULL); + if (from == NULL || to == NULL) { + return -1; + } + 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 -1; + } + + return rv; +} +#endif /* HAVE_SHM_RENAME */ + #ifdef HAVE_SHM_UNLINK /*[clinic input] _posixshmem.shm_unlink @@ -111,6 +158,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..0150a0d2cdb446 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -17288,6 +17288,15 @@ 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 */ + #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