diff options
Diffstat (limited to 'Modules')
-rw-r--r-- | Modules/_multiprocessing/clinic/posixshmem.c.h | 92 | ||||
-rw-r--r-- | Modules/_multiprocessing/posixshmem.c | 743 | ||||
-rw-r--r-- | Modules/_winapi.c | 164 | ||||
-rw-r--r-- | Modules/clinic/_winapi.c.h | 154 |
4 files changed, 483 insertions, 670 deletions
diff --git a/Modules/_multiprocessing/clinic/posixshmem.c.h b/Modules/_multiprocessing/clinic/posixshmem.c.h new file mode 100644 index 0000000000..20abddc0a2 --- /dev/null +++ b/Modules/_multiprocessing/clinic/posixshmem.c.h @@ -0,0 +1,92 @@ +/*[clinic input] +preserve +[clinic start generated code]*/ + +#if defined(HAVE_SHM_OPEN) + +PyDoc_STRVAR(_posixshmem_shm_open__doc__, +"shm_open($module, /, path, flags, mode=511)\n" +"--\n" +"\n" +"Open a shared memory object. Returns a file descriptor (integer)."); + +#define _POSIXSHMEM_SHM_OPEN_METHODDEF \ + {"shm_open", (PyCFunction)(void(*)(void))_posixshmem_shm_open, METH_FASTCALL|METH_KEYWORDS, _posixshmem_shm_open__doc__}, + +static int +_posixshmem_shm_open_impl(PyObject *module, PyObject *path, int flags, + int mode); + +static PyObject * +_posixshmem_shm_open(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + static const char * const _keywords[] = {"path", "flags", "mode", NULL}; + static _PyArg_Parser _parser = {"Ui|i:shm_open", _keywords, 0}; + PyObject *path; + int flags; + int mode = 511; + int _return_value; + + if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, + &path, &flags, &mode)) { + goto exit; + } + _return_value = _posixshmem_shm_open_impl(module, path, flags, mode); + if ((_return_value == -1) && PyErr_Occurred()) { + goto exit; + } + return_value = PyLong_FromLong((long)_return_value); + +exit: + return return_value; +} + +#endif /* defined(HAVE_SHM_OPEN) */ + +#if defined(HAVE_SHM_UNLINK) + +PyDoc_STRVAR(_posixshmem_shm_unlink__doc__, +"shm_unlink($module, /, path)\n" +"--\n" +"\n" +"Remove a shared memory object (similar to unlink()).\n" +"\n" +"Remove a shared memory object name, and, once all processes have unmapped\n" +"the object, de-allocates and destroys the contents of the associated memory\n" +"region."); + +#define _POSIXSHMEM_SHM_UNLINK_METHODDEF \ + {"shm_unlink", (PyCFunction)(void(*)(void))_posixshmem_shm_unlink, METH_FASTCALL|METH_KEYWORDS, _posixshmem_shm_unlink__doc__}, + +static PyObject * +_posixshmem_shm_unlink_impl(PyObject *module, PyObject *path); + +static PyObject * +_posixshmem_shm_unlink(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + static const char * const _keywords[] = {"path", NULL}; + static _PyArg_Parser _parser = {"U:shm_unlink", _keywords, 0}; + PyObject *path; + + if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, + &path)) { + goto exit; + } + return_value = _posixshmem_shm_unlink_impl(module, path); + +exit: + return return_value; +} + +#endif /* defined(HAVE_SHM_UNLINK) */ + +#ifndef _POSIXSHMEM_SHM_OPEN_METHODDEF + #define _POSIXSHMEM_SHM_OPEN_METHODDEF +#endif /* !defined(_POSIXSHMEM_SHM_OPEN_METHODDEF) */ + +#ifndef _POSIXSHMEM_SHM_UNLINK_METHODDEF + #define _POSIXSHMEM_SHM_UNLINK_METHODDEF +#endif /* !defined(_POSIXSHMEM_SHM_UNLINK_METHODDEF) */ +/*[clinic end generated code: output=ff9cf0bc9b8baddf input=a9049054013a1b77]*/ diff --git a/Modules/_multiprocessing/posixshmem.c b/Modules/_multiprocessing/posixshmem.c index 7dd29f405e..2049dbbc6f 100644 --- a/Modules/_multiprocessing/posixshmem.c +++ b/Modules/_multiprocessing/posixshmem.c @@ -1,31 +1,5 @@ /* -posixshmem - A Python module for accessing POSIX 1003.1b-1993 shared memory. - -Copyright (c) 2012, Philip Semanchuk -Copyright (c) 2018, 2019, Davin Potts -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of posixshmem nor the names of its contributors may - be used to endorse or promote products derived from this software - without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY ITS CONTRIBUTORS ''AS IS'' AND ANY -EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL Philip Semanchuk BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +posixshmem - A Python extension that provides shm_open() and shm_unlink() */ #define PY_SSIZE_T_CLEAN @@ -33,627 +7,106 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include <Python.h> #include "structmember.h" -#include <time.h> -#include <sys/time.h> -#include <fcntl.h> -#include <errno.h> -#include <stdio.h> - -// For shared memory stuff -#include <sys/stat.h> +// for shm_open() and shm_unlink() +#ifdef HAVE_SYS_MMAN_H #include <sys/mman.h> - -/* SEM_FAILED is defined as an int in Apple's headers, and this makes the -compiler complain when I compare it to a pointer. Python faced the same -problem (issue 9586) and I copied their solution here. -ref: http://bugs.python.org/issue9586 - -Note that in /Developer/SDKs/MacOSX10.4u.sdk/usr/include/sys/semaphore.h, -SEM_FAILED is #defined as -1 and that's apparently the definition used by -Python when building. In /usr/include/sys/semaphore.h, it's defined -as ((sem_t *)-1). -*/ -#ifdef __APPLE__ - #undef SEM_FAILED - #define SEM_FAILED ((sem_t *)-1) #endif -/* POSIX says that a mode_t "shall be an integer type". To avoid the need -for a specific get_mode function for each type, I'll just stuff the mode into -a long and mention it in the Xxx_members list for each type. -ref: http://www.opengroup.org/onlinepubs/000095399/basedefs/sys/types.h.html -*/ - -typedef struct { - PyObject_HEAD - char *name; - long mode; - int fd; -} SharedMemory; - - -// FreeBSD (and perhaps other BSDs) limit names to 14 characters. In the -// code below, strings of this length are allocated on the stack, so -// increase this gently or change that code to use malloc(). -#define MAX_SAFE_NAME_LENGTH 14 - - -/* Struct to contain an IPC object name which can be None */ -typedef struct { - int is_none; - char *name; -} NoneableName; - +/*[clinic input] +module _posixshmem +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=a416734e49164bf8]*/ /* - Exceptions for this module -*/ - -static PyObject *pBaseException; -static PyObject *pPermissionsException; -static PyObject *pExistentialException; - - -#ifdef POSIX_IPC_DEBUG -#define DPRINTF(fmt, args...) fprintf(stderr, "+++ " fmt, ## args) -#else -#define DPRINTF(fmt, args...) -#endif - -static char * -bytes_to_c_string(PyObject* o, int lock) { -/* Convert a bytes object to a char *. Optionally lock the buffer if it is a - bytes array. - This code swiped directly from Python 3.1's posixmodule.c by Philip S. - The name there is bytes2str(). -*/ - if (PyBytes_Check(o)) - return PyBytes_AsString(o); - else if (PyByteArray_Check(o)) { - if (lock && PyObject_GetBuffer(o, NULL, 0) < 0) - /* On a bytearray, this should not fail. */ - PyErr_BadInternalCall(); - return PyByteArray_AsString(o); - } else { - /* The FS converter should have verified that this - is either bytes or bytearray. */ - Py_FatalError("bad object passed to bytes2str"); - /* not reached. */ - return ""; - } -} - -static void -release_bytes(PyObject* o) - /* Release the lock, decref the object. - This code swiped directly from Python 3.1's posixmodule.c by Philip S. - */ -{ - if (PyByteArray_Check(o)) - o->ob_type->tp_as_buffer->bf_releasebuffer(NULL, 0); - Py_DECREF(o); -} - - -static int -random_in_range(int min, int max) { - // returns a random int N such that min <= N <= max - int diff = (max - min) + 1; - - // ref: http://www.c-faq.com/lib/randrange.html - return ((int)((double)rand() / ((double)RAND_MAX + 1) * diff)) + min; -} - - -static -int create_random_name(char *name) { - // The random name is always lowercase so that this code will work - // on case-insensitive file systems. It always starts with a forward - // slash. - int length; - char *alphabet = "abcdefghijklmnopqrstuvwxyz"; - int i; + * + * Module-level functions & meta stuff + * + */ - // Generate a random length for the name. I subtract 1 from the - // MAX_SAFE_NAME_LENGTH in order to allow for the name's leading "/". - length = random_in_range(6, MAX_SAFE_NAME_LENGTH - 1); +#ifdef HAVE_SHM_OPEN +/*[clinic input] +_posixshmem.shm_open -> int + path: unicode + flags: int + mode: int = 0o777 - name[0] = '/'; - name[length] = '\0'; - i = length; - while (--i) - name[i] = alphabet[random_in_range(0, 25)]; +# "shm_open(path, flags, mode=0o777)\n\n\ - return length; -} +Open a shared memory object. Returns a file descriptor (integer). +[clinic start generated code]*/ static int -convert_name_param(PyObject *py_name_param, void *checked_name) { - /* Verifies that the py_name_param is either None or a string. - If it's a string, checked_name->name points to a PyMalloc-ed buffer - holding a NULL-terminated C version of the string when this function - concludes. The caller is responsible for releasing the buffer. - */ - int rc = 0; - NoneableName *p_name = (NoneableName *)checked_name; - PyObject *py_name_as_bytes = NULL; - char *p_name_as_c_string = NULL; - - DPRINTF("inside convert_name_param\n"); - DPRINTF("PyBytes_Check() = %d \n", PyBytes_Check(py_name_param)); - DPRINTF("PyString_Check() = %d \n", PyString_Check(py_name_param)); - DPRINTF("PyUnicode_Check() = %d \n", PyUnicode_Check(py_name_param)); - - p_name->is_none = 0; - - // The name can be None or a Python string - if (py_name_param == Py_None) { - DPRINTF("name is None\n"); - rc = 1; - p_name->is_none = 1; +_posixshmem_shm_open_impl(PyObject *module, PyObject *path, int flags, + int mode) +/*[clinic end generated code: output=8d110171a4fa20df input=e83b58fa802fac25]*/ +{ + int fd; + int async_err = 0; + const char *name = PyUnicode_AsUTF8(path); + if (name == NULL) { + return -1; } - else if (PyUnicode_Check(py_name_param) || PyBytes_Check(py_name_param)) { - DPRINTF("name is Unicode or bytes\n"); - // The caller passed me a Unicode string or a byte array; I need a - // char *. Getting from one to the other takes a couple steps. - - if (PyUnicode_Check(py_name_param)) { - DPRINTF("name is Unicode\n"); - // PyUnicode_FSConverter() converts the Unicode object into a - // bytes or a bytearray object. (Why can't it be one or the other?) - PyUnicode_FSConverter(py_name_param, &py_name_as_bytes); - } - else { - DPRINTF("name is bytes\n"); - // Make a copy of the name param. - py_name_as_bytes = PyBytes_FromObject(py_name_param); - } - - // bytes_to_c_string() returns a pointer to the buffer. - p_name_as_c_string = bytes_to_c_string(py_name_as_bytes, 0); - - // PyMalloc memory and copy the user-supplied name to it. - p_name->name = (char *)PyMem_Malloc(strlen(p_name_as_c_string) + 1); - if (p_name->name) { - rc = 1; - strcpy(p_name->name, p_name_as_c_string); - } - else - PyErr_SetString(PyExc_MemoryError, "Out of memory"); - - // The bytes version of the name isn't useful to me, and per the - // documentation for PyUnicode_FSConverter(), I am responsible for - // releasing it when I'm done. - release_bytes(py_name_as_bytes); + do { + Py_BEGIN_ALLOW_THREADS + fd = shm_open(name, flags, mode); + Py_END_ALLOW_THREADS + } while (fd < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); + + if (fd < 0) { + if (!async_err) + PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, path); + return -1; } - else - PyErr_SetString(PyExc_TypeError, "Name must be None or a string"); - return rc; + return fd; } +#endif /* HAVE_SHM_OPEN */ +#ifdef HAVE_SHM_UNLINK +/*[clinic input] +_posixshmem.shm_unlink + path: unicode +Remove a shared memory object (similar to unlink()). -/* ===== Begin Shared Memory implementation functions ===== */ - -static PyObject * -shm_str(SharedMemory *self) { - return PyUnicode_FromString(self->name ? self->name : "(no name)"); -} - -static PyObject * -shm_repr(SharedMemory *self) { - char mode[32]; - - sprintf(mode, "0%o", (int)(self->mode)); +Remove a shared memory object name, and, once all processes have unmapped +the object, de-allocates and destroys the contents of the associated memory +region. - return PyUnicode_FromFormat("_posixshmem.SharedMemory(\"%s\", mode=%s)", - self->name, mode); -} +[clinic start generated code]*/ static PyObject * -my_shm_unlink(const char *name) { - DPRINTF("unlinking shm name %s\n", name); - if (-1 == shm_unlink(name)) { - switch (errno) { - case EACCES: - PyErr_SetString(pPermissionsException, "Permission denied"); - break; - - case ENOENT: - PyErr_SetString(pExistentialException, - "No shared memory exists with the specified name"); - break; - - case ENAMETOOLONG: - PyErr_SetString(PyExc_ValueError, "The name is too long"); - break; - - default: - PyErr_SetFromErrno(PyExc_OSError); - break; - } - - goto error_return; - } - - Py_RETURN_NONE; - - error_return: - return NULL; -} - - -static PyObject * -SharedMemory_new(PyTypeObject *type, PyObject *args, PyObject *kwlist) { - SharedMemory *self; - - self = (SharedMemory *)type->tp_alloc(type, 0); - - return (PyObject *)self; -} - - -static int -SharedMemory_init(SharedMemory *self, PyObject *args, PyObject *keywords) { - NoneableName name; - char temp_name[MAX_SAFE_NAME_LENGTH + 1]; - unsigned int flags = 0; - unsigned long size = 0; - int read_only = 0; - static char *keyword_list[ ] = {"name", "flags", "mode", "size", "read_only", NULL}; - - // First things first -- initialize the self struct. - self->name = NULL; - self->fd = 0; - self->mode = 0600; - - if (!PyArg_ParseTupleAndKeywords(args, keywords, "O&|Iiki", keyword_list, - &convert_name_param, &name, &flags, - &(self->mode), &size, &read_only)) - goto error_return; - - if ( !(flags & O_CREAT) && (flags & O_EXCL) ) { - PyErr_SetString(PyExc_ValueError, - "O_EXCL must be combined with O_CREAT"); - goto error_return; - } - - if (name.is_none && ((flags & O_EXCL) != O_EXCL)) { - PyErr_SetString(PyExc_ValueError, - "Name can only be None if O_EXCL is set"); - goto error_return; - } - - flags |= (read_only ? O_RDONLY : O_RDWR); - - if (name.is_none) { - // (name == None) ==> generate a name for the caller - do { - errno = 0; - create_random_name(temp_name); - - DPRINTF("calling shm_open, name=%s, flags=0x%x, mode=0%o\n", - temp_name, flags, (int)self->mode); - self->fd = shm_open(temp_name, flags, (mode_t)self->mode); - - } while ( (-1 == self->fd) && (EEXIST == errno) ); - - // PyMalloc memory and copy the randomly-generated name to it. - self->name = (char *)PyMem_Malloc(strlen(temp_name) + 1); - if (self->name) - strcpy(self->name, temp_name); - else { - PyErr_SetString(PyExc_MemoryError, "Out of memory"); - goto error_return; - } - } - else { - // (name != None) ==> use name supplied by the caller. It was - // already converted to C by convert_name_param(). - self->name = name.name; - - DPRINTF("calling shm_open, name=%s, flags=0x%x, mode=0%o\n", - self->name, flags, (int)self->mode); - self->fd = shm_open(self->name, flags, (mode_t)self->mode); - } - - DPRINTF("shm fd = %d\n", self->fd); - - if (-1 == self->fd) { - self->fd = 0; - switch (errno) { - case EACCES: - PyErr_Format(pPermissionsException, - "No permission to %s this segment", - (flags & O_TRUNC) ? "truncate" : "access" - ); - break; - - case EEXIST: - PyErr_SetString(pExistentialException, - "Shared memory with the specified name already exists"); - break; - - case ENOENT: - PyErr_SetString(pExistentialException, - "No shared memory exists with the specified name"); - break; - - case EINVAL: - PyErr_SetString(PyExc_ValueError, "Invalid parameter(s)"); - break; - - case EMFILE: - PyErr_SetString(PyExc_OSError, - "This process already has the maximum number of files open"); - break; - - case ENFILE: - PyErr_SetString(PyExc_OSError, - "The system limit on the total number of open files has been reached"); - break; - - case ENAMETOOLONG: - PyErr_SetString(PyExc_ValueError, - "The name is too long"); - break; - - default: - PyErr_SetFromErrno(PyExc_OSError); - break; - } - - goto error_return; - } - else { - if (size) { - DPRINTF("calling ftruncate, fd = %d, size = %ld\n", self->fd, size); - if (-1 == ftruncate(self->fd, (off_t)size)) { - // The code below will raise a Python error. Since that error - // is raised during __init__(), it will look to the caller - // as if object creation failed entirely. Here I clean up - // the system object I just created. - close(self->fd); - shm_unlink(self->name); - - // ftruncate can return a ton of different errors, but most - // are not relevant or are extremely unlikely. - switch (errno) { - case EINVAL: - PyErr_SetString(PyExc_ValueError, - "The size is invalid or the memory is read-only"); - break; - - case EFBIG: - PyErr_SetString(PyExc_ValueError, - "The size is too large"); - break; - - case EROFS: - case EACCES: - PyErr_SetString(pPermissionsException, - "The memory is read-only"); - break; - - default: - PyErr_SetFromErrno(PyExc_OSError); - break; - } - - goto error_return; - } - } - } - - return 0; - - error_return: - return -1; -} - - -static void SharedMemory_dealloc(SharedMemory *self) { - DPRINTF("dealloc\n"); - PyMem_Free(self->name); - self->name = NULL; - - Py_TYPE(self)->tp_free((PyObject*)self); -} - - -PyObject * -SharedMemory_getsize(SharedMemory *self, void *closure) { - struct stat fileinfo; - off_t size = -1; - - if (0 == fstat(self->fd, &fileinfo)) - size = fileinfo.st_size; - else { - switch (errno) { - case EBADF: - case EINVAL: - PyErr_SetString(pExistentialException, - "The segment does not exist"); - break; - - default: - PyErr_SetFromErrno(PyExc_OSError); - break; - } - - goto error_return; +_posixshmem_shm_unlink_impl(PyObject *module, PyObject *path) +/*[clinic end generated code: output=42f8b23d134b9ff5 input=8dc0f87143e3b300]*/ +{ + int rv; + int async_err = 0; + const char *name = PyUnicode_AsUTF8(path); + if (name == NULL) { + return NULL; } - - return Py_BuildValue("k", (unsigned long)size); - - error_return: - return NULL; -} - - -PyObject * -SharedMemory_close_fd(SharedMemory *self) { - if (self->fd) { - if (-1 == close(self->fd)) { - switch (errno) { - case EBADF: - PyErr_SetString(PyExc_ValueError, - "The file descriptor is invalid"); - break; - - default: - PyErr_SetFromErrno(PyExc_OSError); - break; - } - - goto error_return; - } + do { + Py_BEGIN_ALLOW_THREADS + rv = shm_unlink(name); + Py_END_ALLOW_THREADS + } while (rv < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); + + if (rv < 0) { + if (!async_err) + PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, path); + return NULL; } Py_RETURN_NONE; - - error_return: - return NULL; -} - - -PyObject * -SharedMemory_unlink(SharedMemory *self) { - return my_shm_unlink(self->name); -} - - -/* ===== End Shared Memory functions ===== */ - - -/* - * - * Shared memory meta stuff for describing myself to Python - * - */ - - -static PyMemberDef SharedMemory_members[] = { - { "name", - T_STRING, - offsetof(SharedMemory, name), - READONLY, - "The name specified in the constructor" - }, - { "fd", - T_INT, - offsetof(SharedMemory, fd), - READONLY, - "Shared memory segment file descriptor" - }, - { "mode", - T_LONG, - offsetof(SharedMemory, mode), - READONLY, - "The mode specified in the constructor" - }, - {NULL} /* Sentinel */ -}; - - -static PyMethodDef SharedMemory_methods[] = { - { "close_fd", - (PyCFunction)SharedMemory_close_fd, - METH_NOARGS, - "Closes the file descriptor associated with the shared memory." - }, - { "unlink", - (PyCFunction)SharedMemory_unlink, - METH_NOARGS, - "Unlink (remove) the shared memory." - }, - {NULL, NULL, 0, NULL} /* Sentinel */ -}; - - -static PyGetSetDef SharedMemory_getseters[] = { - // size is read-only - { "size", - (getter)SharedMemory_getsize, - (setter)NULL, - "size", - NULL - }, - {NULL} /* Sentinel */ -}; - - -static PyTypeObject SharedMemoryType = { - PyVarObject_HEAD_INIT(NULL, 0) - "_posixshmem._PosixSharedMemory", // tp_name - sizeof(SharedMemory), // tp_basicsize - 0, // tp_itemsize - (destructor) SharedMemory_dealloc, // tp_dealloc - 0, // tp_print - 0, // tp_getattr - 0, // tp_setattr - 0, // tp_compare - (reprfunc) shm_repr, // tp_repr - 0, // tp_as_number - 0, // tp_as_sequence - 0, // tp_as_mapping - 0, // tp_hash - 0, // tp_call - (reprfunc) shm_str, // tp_str - 0, // tp_getattro - 0, // tp_setattro - 0, // tp_as_buffer - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - // tp_flags - "POSIX shared memory object", // tp_doc - 0, // tp_traverse - 0, // tp_clear - 0, // tp_richcompare - 0, // tp_weaklistoffset - 0, // tp_iter - 0, // tp_iternext - SharedMemory_methods, // tp_methods - SharedMemory_members, // tp_members - SharedMemory_getseters, // tp_getset - 0, // tp_base - 0, // tp_dict - 0, // tp_descr_get - 0, // tp_descr_set - 0, // tp_dictoffset - (initproc) SharedMemory_init, // tp_init - 0, // tp_alloc - (newfunc) SharedMemory_new, // tp_new - 0, // tp_free - 0, // tp_is_gc - 0 // tp_bases -}; - - -/* - * - * Module-level functions & meta stuff - * - */ - -static PyObject * -posixshmem_unlink_shared_memory(PyObject *self, PyObject *args) { - const char *name; - - if (!PyArg_ParseTuple(args, "s", &name)) - return NULL; - else - return my_shm_unlink(name); } +#endif /* HAVE_SHM_UNLINK */ +#include "clinic/posixshmem.c.h" static PyMethodDef module_methods[ ] = { - { "unlink_shared_memory", - (PyCFunction)posixshmem_unlink_shared_memory, - METH_VARARGS, - "Unlink shared memory" - }, + _POSIXSHMEM_SHM_OPEN_METHODDEF + _POSIXSHMEM_SHM_UNLINK_METHODDEF {NULL} /* Sentinel */ }; @@ -664,61 +117,15 @@ static struct PyModuleDef this_module = { "POSIX shared memory module", // m_doc -1, // m_size (space allocated for module globals) module_methods, // m_methods - NULL, // m_reload - NULL, // m_traverse - NULL, // m_clear - NULL // m_free }; /* Module init function */ PyMODINIT_FUNC PyInit__posixshmem(void) { PyObject *module; - PyObject *module_dict; - - // I call this in case I'm asked to create any random names. - srand((unsigned int)time(NULL)); - module = PyModule_Create(&this_module); - - if (!module) - goto error_return; - - if (PyType_Ready(&SharedMemoryType) < 0) - goto error_return; - - Py_INCREF(&SharedMemoryType); - PyModule_AddObject(module, "_PosixSharedMemory", (PyObject *)&SharedMemoryType); - - - PyModule_AddStringConstant(module, "__copyright__", "Copyright 2012 Philip Semanchuk, 2018-2019 Davin Potts"); - - PyModule_AddIntConstant(module, "O_CREAT", O_CREAT); - PyModule_AddIntConstant(module, "O_EXCL", O_EXCL); - PyModule_AddIntConstant(module, "O_CREX", O_CREAT | O_EXCL); - PyModule_AddIntConstant(module, "O_TRUNC", O_TRUNC); - - if (!(module_dict = PyModule_GetDict(module))) - goto error_return; - - // Exceptions - if (!(pBaseException = PyErr_NewException("_posixshmem.Error", NULL, NULL))) - goto error_return; - else - PyDict_SetItemString(module_dict, "Error", pBaseException); - - if (!(pPermissionsException = PyErr_NewException("_posixshmem.PermissionsError", pBaseException, NULL))) - goto error_return; - else - PyDict_SetItemString(module_dict, "PermissionsError", pPermissionsException); - - if (!(pExistentialException = PyErr_NewException("_posixshmem.ExistentialError", pBaseException, NULL))) - goto error_return; - else - PyDict_SetItemString(module_dict, "ExistentialError", pExistentialException); - + if (!module) { + return NULL; + } return module; - - error_return: - return NULL; } diff --git a/Modules/_winapi.c b/Modules/_winapi.c index cdb45c23e7..e7b221d888 100644 --- a/Modules/_winapi.c +++ b/Modules/_winapi.c @@ -159,6 +159,7 @@ def create_converter(type_, format_unit): create_converter('HANDLE', '" F_HANDLE "') create_converter('HMODULE', '" F_HANDLE "') create_converter('LPSECURITY_ATTRIBUTES', '" F_POINTER "') +create_converter('LPCVOID', '" F_POINTER "') create_converter('BOOL', 'i') # F_BOOL used previously (always 'i') create_converter('DWORD', 'k') # F_DWORD is always "k" (which is much shorter) @@ -186,8 +187,17 @@ class DWORD_return_converter(CReturnConverter): self.err_occurred_if("_return_value == PY_DWORD_MAX", data) data.return_conversion.append( 'return_value = Py_BuildValue("k", _return_value);\n') + +class LPVOID_return_converter(CReturnConverter): + type = 'LPVOID' + + def render(self, function, data): + self.declare(data) + self.err_occurred_if("_return_value == NULL", data) + data.return_conversion.append( + 'return_value = HANDLE_TO_PYNUM(_return_value);\n') [python start generated code]*/ -/*[python end generated code: output=da39a3ee5e6b4b0d input=27456f8555228b62]*/ +/*[python end generated code: output=da39a3ee5e6b4b0d input=79464c61a31ae932]*/ #include "clinic/_winapi.c.h" @@ -465,6 +475,41 @@ _winapi_CreateFile_impl(PyObject *module, LPCTSTR file_name, } /*[clinic input] +_winapi.CreateFileMapping -> HANDLE + + file_handle: HANDLE + security_attributes: LPSECURITY_ATTRIBUTES + protect: DWORD + max_size_high: DWORD + max_size_low: DWORD + name: LPCWSTR + / +[clinic start generated code]*/ + +static HANDLE +_winapi_CreateFileMapping_impl(PyObject *module, HANDLE file_handle, + LPSECURITY_ATTRIBUTES security_attributes, + DWORD protect, DWORD max_size_high, + DWORD max_size_low, LPCWSTR name) +/*[clinic end generated code: output=6c0a4d5cf7f6fcc6 input=3dc5cf762a74dee8]*/ +{ + HANDLE handle; + + Py_BEGIN_ALLOW_THREADS + handle = CreateFileMappingW(file_handle, security_attributes, + protect, max_size_high, max_size_low, + name); + Py_END_ALLOW_THREADS + + if (handle == NULL) { + PyErr_SetFromWindowsErrWithUnicodeFilename(0, name); + handle = INVALID_HANDLE_VALUE; + } + + return handle; +} + +/*[clinic input] _winapi.CreateJunction src_path: LPWSTR @@ -1296,6 +1341,64 @@ _winapi_GetVersion_impl(PyObject *module) #pragma warning(pop) /*[clinic input] +_winapi.MapViewOfFile -> LPVOID + + file_map: HANDLE + desired_access: DWORD + file_offset_high: DWORD + file_offset_low: DWORD + number_bytes: size_t + / +[clinic start generated code]*/ + +static LPVOID +_winapi_MapViewOfFile_impl(PyObject *module, HANDLE file_map, + DWORD desired_access, DWORD file_offset_high, + DWORD file_offset_low, size_t number_bytes) +/*[clinic end generated code: output=f23b1ee4823663e3 input=177471073be1a103]*/ +{ + LPVOID address; + + Py_BEGIN_ALLOW_THREADS + address = MapViewOfFile(file_map, desired_access, file_offset_high, + file_offset_low, number_bytes); + Py_END_ALLOW_THREADS + + if (address == NULL) + PyErr_SetFromWindowsErr(0); + + return address; +} + +/*[clinic input] +_winapi.OpenFileMapping -> HANDLE + + desired_access: DWORD + inherit_handle: BOOL + name: LPCWSTR + / +[clinic start generated code]*/ + +static HANDLE +_winapi_OpenFileMapping_impl(PyObject *module, DWORD desired_access, + BOOL inherit_handle, LPCWSTR name) +/*[clinic end generated code: output=08cc44def1cb11f1 input=131f2a405359de7f]*/ +{ + HANDLE handle; + + Py_BEGIN_ALLOW_THREADS + handle = OpenFileMappingW(desired_access, inherit_handle, name); + Py_END_ALLOW_THREADS + + if (handle == NULL) { + PyErr_SetFromWindowsErrWithUnicodeFilename(0, name); + handle = INVALID_HANDLE_VALUE; + } + + return handle; +} + +/*[clinic input] _winapi.OpenProcess -> HANDLE desired_access: DWORD @@ -1491,6 +1594,32 @@ _winapi_TerminateProcess_impl(PyObject *module, HANDLE handle, } /*[clinic input] +_winapi.VirtualQuerySize -> size_t + + address: LPCVOID + / +[clinic start generated code]*/ + +static size_t +_winapi_VirtualQuerySize_impl(PyObject *module, LPCVOID address) +/*[clinic end generated code: output=40c8e0ff5ec964df input=6b784a69755d0bb6]*/ +{ + SIZE_T size_of_buf; + MEMORY_BASIC_INFORMATION mem_basic_info; + SIZE_T region_size; + + Py_BEGIN_ALLOW_THREADS + size_of_buf = VirtualQuery(address, &mem_basic_info, sizeof(mem_basic_info)); + Py_END_ALLOW_THREADS + + if (size_of_buf == 0) + PyErr_SetFromWindowsErr(0); + + region_size = mem_basic_info.RegionSize; + return region_size; +} + +/*[clinic input] _winapi.WaitNamedPipe name: LPCTSTR @@ -1719,6 +1848,7 @@ static PyMethodDef winapi_functions[] = { _WINAPI_CLOSEHANDLE_METHODDEF _WINAPI_CONNECTNAMEDPIPE_METHODDEF _WINAPI_CREATEFILE_METHODDEF + _WINAPI_CREATEFILEMAPPING_METHODDEF _WINAPI_CREATENAMEDPIPE_METHODDEF _WINAPI_CREATEPIPE_METHODDEF _WINAPI_CREATEPROCESS_METHODDEF @@ -1731,11 +1861,14 @@ static PyMethodDef winapi_functions[] = { _WINAPI_GETMODULEFILENAME_METHODDEF _WINAPI_GETSTDHANDLE_METHODDEF _WINAPI_GETVERSION_METHODDEF + _WINAPI_MAPVIEWOFFILE_METHODDEF + _WINAPI_OPENFILEMAPPING_METHODDEF _WINAPI_OPENPROCESS_METHODDEF _WINAPI_PEEKNAMEDPIPE_METHODDEF _WINAPI_READFILE_METHODDEF _WINAPI_SETNAMEDPIPEHANDLESTATE_METHODDEF _WINAPI_TERMINATEPROCESS_METHODDEF + _WINAPI_VIRTUALQUERYSIZE_METHODDEF _WINAPI_WAITNAMEDPIPE_METHODDEF _WINAPI_WAITFORMULTIPLEOBJECTS_METHODDEF _WINAPI_WAITFORSINGLEOBJECT_METHODDEF @@ -1799,11 +1932,34 @@ PyInit__winapi(void) WINAPI_CONSTANT(F_DWORD, FILE_FLAG_OVERLAPPED); WINAPI_CONSTANT(F_DWORD, FILE_GENERIC_READ); WINAPI_CONSTANT(F_DWORD, FILE_GENERIC_WRITE); + WINAPI_CONSTANT(F_DWORD, FILE_MAP_ALL_ACCESS); + WINAPI_CONSTANT(F_DWORD, FILE_MAP_COPY); + WINAPI_CONSTANT(F_DWORD, FILE_MAP_EXECUTE); + WINAPI_CONSTANT(F_DWORD, FILE_MAP_READ); + WINAPI_CONSTANT(F_DWORD, FILE_MAP_WRITE); WINAPI_CONSTANT(F_DWORD, GENERIC_READ); WINAPI_CONSTANT(F_DWORD, GENERIC_WRITE); WINAPI_CONSTANT(F_DWORD, INFINITE); + WINAPI_CONSTANT(F_HANDLE, INVALID_HANDLE_VALUE); + WINAPI_CONSTANT(F_DWORD, MEM_COMMIT); + WINAPI_CONSTANT(F_DWORD, MEM_FREE); + WINAPI_CONSTANT(F_DWORD, MEM_IMAGE); + WINAPI_CONSTANT(F_DWORD, MEM_MAPPED); + WINAPI_CONSTANT(F_DWORD, MEM_PRIVATE); + WINAPI_CONSTANT(F_DWORD, MEM_RESERVE); WINAPI_CONSTANT(F_DWORD, NMPWAIT_WAIT_FOREVER); WINAPI_CONSTANT(F_DWORD, OPEN_EXISTING); + WINAPI_CONSTANT(F_DWORD, PAGE_EXECUTE); + WINAPI_CONSTANT(F_DWORD, PAGE_EXECUTE_READ); + WINAPI_CONSTANT(F_DWORD, PAGE_EXECUTE_READWRITE); + WINAPI_CONSTANT(F_DWORD, PAGE_EXECUTE_WRITECOPY); + WINAPI_CONSTANT(F_DWORD, PAGE_GUARD); + WINAPI_CONSTANT(F_DWORD, PAGE_NOACCESS); + WINAPI_CONSTANT(F_DWORD, PAGE_NOCACHE); + WINAPI_CONSTANT(F_DWORD, PAGE_READONLY); + WINAPI_CONSTANT(F_DWORD, PAGE_READWRITE); + WINAPI_CONSTANT(F_DWORD, PAGE_WRITECOMBINE); + WINAPI_CONSTANT(F_DWORD, PAGE_WRITECOPY); WINAPI_CONSTANT(F_DWORD, PIPE_ACCESS_DUPLEX); WINAPI_CONSTANT(F_DWORD, PIPE_ACCESS_INBOUND); WINAPI_CONSTANT(F_DWORD, PIPE_READMODE_MESSAGE); @@ -1812,6 +1968,12 @@ PyInit__winapi(void) WINAPI_CONSTANT(F_DWORD, PIPE_WAIT); WINAPI_CONSTANT(F_DWORD, PROCESS_ALL_ACCESS); WINAPI_CONSTANT(F_DWORD, PROCESS_DUP_HANDLE); + WINAPI_CONSTANT(F_DWORD, SEC_COMMIT); + WINAPI_CONSTANT(F_DWORD, SEC_IMAGE); + WINAPI_CONSTANT(F_DWORD, SEC_LARGE_PAGES); + WINAPI_CONSTANT(F_DWORD, SEC_NOCACHE); + WINAPI_CONSTANT(F_DWORD, SEC_RESERVE); + WINAPI_CONSTANT(F_DWORD, SEC_WRITECOMBINE); WINAPI_CONSTANT(F_DWORD, STARTF_USESHOWWINDOW); WINAPI_CONSTANT(F_DWORD, STARTF_USESTDHANDLES); WINAPI_CONSTANT(F_DWORD, STD_INPUT_HANDLE); diff --git a/Modules/clinic/_winapi.c.h b/Modules/clinic/_winapi.c.h index f1158a0062..e21f2bc2b6 100644 --- a/Modules/clinic/_winapi.c.h +++ b/Modules/clinic/_winapi.c.h @@ -168,6 +168,50 @@ exit: return return_value; } +PyDoc_STRVAR(_winapi_CreateFileMapping__doc__, +"CreateFileMapping($module, file_handle, security_attributes, protect,\n" +" max_size_high, max_size_low, name, /)\n" +"--\n" +"\n"); + +#define _WINAPI_CREATEFILEMAPPING_METHODDEF \ + {"CreateFileMapping", (PyCFunction)(void(*)(void))_winapi_CreateFileMapping, METH_FASTCALL, _winapi_CreateFileMapping__doc__}, + +static HANDLE +_winapi_CreateFileMapping_impl(PyObject *module, HANDLE file_handle, + LPSECURITY_ATTRIBUTES security_attributes, + DWORD protect, DWORD max_size_high, + DWORD max_size_low, LPCWSTR name); + +static PyObject * +_winapi_CreateFileMapping(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + HANDLE file_handle; + LPSECURITY_ATTRIBUTES security_attributes; + DWORD protect; + DWORD max_size_high; + DWORD max_size_low; + LPCWSTR name; + HANDLE _return_value; + + if (!_PyArg_ParseStack(args, nargs, "" F_HANDLE "" F_POINTER "kkku:CreateFileMapping", + &file_handle, &security_attributes, &protect, &max_size_high, &max_size_low, &name)) { + goto exit; + } + _return_value = _winapi_CreateFileMapping_impl(module, file_handle, security_attributes, protect, max_size_high, max_size_low, name); + if ((_return_value == INVALID_HANDLE_VALUE) && PyErr_Occurred()) { + goto exit; + } + if (_return_value == NULL) { + Py_RETURN_NONE; + } + return_value = HANDLE_TO_PYNUM(_return_value); + +exit: + return return_value; +} + PyDoc_STRVAR(_winapi_CreateJunction__doc__, "CreateJunction($module, src_path, dst_path, /)\n" "--\n" @@ -602,6 +646,83 @@ exit: return return_value; } +PyDoc_STRVAR(_winapi_MapViewOfFile__doc__, +"MapViewOfFile($module, file_map, desired_access, file_offset_high,\n" +" file_offset_low, number_bytes, /)\n" +"--\n" +"\n"); + +#define _WINAPI_MAPVIEWOFFILE_METHODDEF \ + {"MapViewOfFile", (PyCFunction)(void(*)(void))_winapi_MapViewOfFile, METH_FASTCALL, _winapi_MapViewOfFile__doc__}, + +static LPVOID +_winapi_MapViewOfFile_impl(PyObject *module, HANDLE file_map, + DWORD desired_access, DWORD file_offset_high, + DWORD file_offset_low, size_t number_bytes); + +static PyObject * +_winapi_MapViewOfFile(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + HANDLE file_map; + DWORD desired_access; + DWORD file_offset_high; + DWORD file_offset_low; + size_t number_bytes; + LPVOID _return_value; + + if (!_PyArg_ParseStack(args, nargs, "" F_HANDLE "kkkO&:MapViewOfFile", + &file_map, &desired_access, &file_offset_high, &file_offset_low, _PyLong_Size_t_Converter, &number_bytes)) { + goto exit; + } + _return_value = _winapi_MapViewOfFile_impl(module, file_map, desired_access, file_offset_high, file_offset_low, number_bytes); + if ((_return_value == NULL) && PyErr_Occurred()) { + goto exit; + } + return_value = HANDLE_TO_PYNUM(_return_value); + +exit: + return return_value; +} + +PyDoc_STRVAR(_winapi_OpenFileMapping__doc__, +"OpenFileMapping($module, desired_access, inherit_handle, name, /)\n" +"--\n" +"\n"); + +#define _WINAPI_OPENFILEMAPPING_METHODDEF \ + {"OpenFileMapping", (PyCFunction)(void(*)(void))_winapi_OpenFileMapping, METH_FASTCALL, _winapi_OpenFileMapping__doc__}, + +static HANDLE +_winapi_OpenFileMapping_impl(PyObject *module, DWORD desired_access, + BOOL inherit_handle, LPCWSTR name); + +static PyObject * +_winapi_OpenFileMapping(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + DWORD desired_access; + BOOL inherit_handle; + LPCWSTR name; + HANDLE _return_value; + + if (!_PyArg_ParseStack(args, nargs, "kiu:OpenFileMapping", + &desired_access, &inherit_handle, &name)) { + goto exit; + } + _return_value = _winapi_OpenFileMapping_impl(module, desired_access, inherit_handle, name); + if ((_return_value == INVALID_HANDLE_VALUE) && PyErr_Occurred()) { + goto exit; + } + if (_return_value == NULL) { + Py_RETURN_NONE; + } + return_value = HANDLE_TO_PYNUM(_return_value); + +exit: + return return_value; +} + PyDoc_STRVAR(_winapi_OpenProcess__doc__, "OpenProcess($module, desired_access, inherit_handle, process_id, /)\n" "--\n" @@ -764,6 +885,37 @@ exit: return return_value; } +PyDoc_STRVAR(_winapi_VirtualQuerySize__doc__, +"VirtualQuerySize($module, address, /)\n" +"--\n" +"\n"); + +#define _WINAPI_VIRTUALQUERYSIZE_METHODDEF \ + {"VirtualQuerySize", (PyCFunction)_winapi_VirtualQuerySize, METH_O, _winapi_VirtualQuerySize__doc__}, + +static size_t +_winapi_VirtualQuerySize_impl(PyObject *module, LPCVOID address); + +static PyObject * +_winapi_VirtualQuerySize(PyObject *module, PyObject *arg) +{ + PyObject *return_value = NULL; + LPCVOID address; + size_t _return_value; + + if (!PyArg_Parse(arg, "" F_POINTER ":VirtualQuerySize", &address)) { + goto exit; + } + _return_value = _winapi_VirtualQuerySize_impl(module, address); + if ((_return_value == (size_t)-1) && PyErr_Occurred()) { + goto exit; + } + return_value = PyLong_FromSize_t(_return_value); + +exit: + return return_value; +} + PyDoc_STRVAR(_winapi_WaitNamedPipe__doc__, "WaitNamedPipe($module, name, timeout, /)\n" "--\n" @@ -945,4 +1097,4 @@ _winapi_GetFileType(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P exit: return return_value; } -/*[clinic end generated code: output=5063c84b2d125488 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=f3897898ea1da99d input=a9049054013a1b77]*/ |