diff options
| -rw-r--r-- | doc/source/whatsnew/0.8.0.rst | 6 | ||||
| -rw-r--r-- | python/apt_pkgmodule.cc | 1 | ||||
| -rw-r--r-- | python/apt_pkgmodule.h | 1 | ||||
| -rw-r--r-- | python/generic.h | 1 | ||||
| -rw-r--r-- | python/lock.cc | 132 |
5 files changed, 141 insertions, 0 deletions
diff --git a/doc/source/whatsnew/0.8.0.rst b/doc/source/whatsnew/0.8.0.rst index 8889cbd9..244da388 100644 --- a/doc/source/whatsnew/0.8.0.rst +++ b/doc/source/whatsnew/0.8.0.rst @@ -79,6 +79,12 @@ Yet another context manager is available for locking the package system:: with apt_pkg.SystemLock(): # do your stuff here +There is also one for file based locking: + + with apt_pkg.FileLock(filename): + # do your stuff here + + Unification of dependency handling ---------------------------------- In apt 0.7, there were three different return types of functions parsing diff --git a/python/apt_pkgmodule.cc b/python/apt_pkgmodule.cc index d4c23d2f..8b8e9c7f 100644 --- a/python/apt_pkgmodule.cc +++ b/python/apt_pkgmodule.cc @@ -652,6 +652,7 @@ extern "C" void initapt_pkg() ADDTYPE(Module,"AcquireItemDesc",&PyAcquireItemDesc_Type); ADDTYPE(Module,"CdromProgress",&PyCdromProgress_Type); ADDTYPE(Module,"SystemLock",&PySystemLock_Type); + ADDTYPE(Module,"FileLock",&PyFileLock_Type); // Tag file constants PyModule_AddObject(Module,"REWRITE_PACKAGE_ORDER", CharCharToList(TFRewritePackageOrder)); diff --git a/python/apt_pkgmodule.h b/python/apt_pkgmodule.h index de70c056..04bce2cc 100644 --- a/python/apt_pkgmodule.h +++ b/python/apt_pkgmodule.h @@ -118,6 +118,7 @@ extern PyTypeObject PyCdromProgress_Type; extern PyTypeObject PyAcquireItemDesc_Type; extern PyTypeObject PyAcquireWorker_Type; extern PyTypeObject PySystemLock_Type; +extern PyTypeObject PyFileLock_Type; #include "python-apt.h" #endif diff --git a/python/generic.h b/python/generic.h index 4a55e9bf..d7f121ce 100644 --- a/python/generic.h +++ b/python/generic.h @@ -54,6 +54,7 @@ typedef int Py_ssize_t; #define PyString_FromStringAndSize PyUnicode_FromStringAndSize #define PyString_AsString PyUnicode_AsString #define PyString_FromFormat PyUnicode_FromFormat +#define PyString_Type PyUnicode_Type #define PyInt_Check PyLong_Check #define PyInt_AsLong PyLong_AsLong // Force 0.7 compatibility to be off in Python 3 builds diff --git a/python/lock.cc b/python/lock.cc index 75665779..d4d45734 100644 --- a/python/lock.cc +++ b/python/lock.cc @@ -131,3 +131,135 @@ PyTypeObject PySystemLock_Type = { 0, // tp_alloc systemlock_new, // tp_new }; + + +/** + * File Based locking. + * + * The counter is increased by every call to filelock_enter() and decreased by + * every call to filelock_exit(). When the counter reaches 0, the underlying + * file descriptor is closed. + * + * Members: + * @member char* filename The name of the file + * @member int lock_count How many times we have locked it. + * @member int fd The filedescriptor returned by GetLock() or 0. + */ +struct filelock_object { + PyObject_HEAD + char *filename; + int lock_count; + int fd; +}; + +static PyObject *filelock_enter(filelock_object *self, PyObject *args) +{ + self->lock_count++; + // If we have no lock yet, get a lock. + if (self->lock_count == 1) { + self->fd = GetLock(self->filename, true); + if (self->fd == -1) { + self->lock_count--; + return HandleErrors(); + } + } + Py_INCREF(self); + return (PyObject *)self; +} + +static PyObject *filelock_exit(filelock_object *self, PyObject *args) +{ + // Count down the lock_count, if it is less than 0, reset it to 0. + self->lock_count--; + if (self->lock_count < 0) + self->lock_count = 0; + if (self->lock_count == 0 && self->fd != 0 && close(self->fd) == -1) { + return PyErr_SetFromErrno(PyExc_OSError); + } + Py_RETURN_FALSE; +} + +static PyObject *filelock_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + char *filename = 0; + char *kwlist[] = {"filename", NULL}; + if (PyArg_ParseTupleAndKeywords(args, kwds, "s:__init__", kwlist, + &filename) == 0) { + return NULL; + } + filelock_object *self = (filelock_object *)type->tp_alloc(type, 0); + // Copy the string into the object. + self->filename = new char[strlen(filename) + 1]; + strcpy(self->filename, filename); + return (PyObject *)self; +} + +static void filelock_dealloc(filelock_object *self) +{ + delete[] self->filename; + ((PyObject*)self)->ob_type->tp_free(self); +} + +static PyMethodDef filelock_methods[] = { + {"__enter__",(PyCFunction)filelock_enter,METH_VARARGS,"Lock the system."}, + {"__exit__",(PyCFunction)filelock_exit,METH_VARARGS,"Unlock the system."}, + {NULL} +}; + +static char *filelock_doc = "SystemLock(filename: str)\n\n" + "Context manager for locking using a file. The lock is established\n" + "as soon as the method __enter__() is called. It is released when\n" + "__exit__() is called.\n\n" + "This should be used via the 'with' statement, e.g.::\n\n" + " with apt_pkg.FileLock(filename):\n" + " ...\n\n" + "Once the block is left, the lock is released automatically. The object\n" + "can be used multiple times::\n\n" + " lock = apt_pkg.FileLock(filename)\n" + " with lock:\n" + " ...\n" + " with lock:\n" + " ...\n\n"; + +PyTypeObject PyFileLock_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_pkg.FileLock", // tp_name + sizeof(filelock_object), // tp_basicsize + 0, // tp_itemsize + // Methods + destructor(filelock_dealloc), // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + 0, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + (Py_TPFLAGS_DEFAULT | // tp_flags + Py_TPFLAGS_BASETYPE), + filelock_doc, // tp_doc + 0, // tp_traverse + 0, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + filelock_methods, // tp_methods + 0, // tp_members + 0, // tp_getset + 0, // tp_base + 0, // tp_dict + 0, // tp_descr_get + 0, // tp_descr_set + 0, // tp_dictoffset + 0, // tp_init + 0, // tp_alloc + filelock_new, // tp_new +}; |
