diff options
author | Jeremy Allison <jra@samba.org> | 2008-12-18 15:40:05 -0800 |
---|---|---|
committer | Jeremy Allison <jra@samba.org> | 2008-12-18 15:40:05 -0800 |
commit | 4283ae489b6e227beba196e8a315a9727f03cc07 (patch) | |
tree | 7308561653b9e52eab8fc13181c0ad41ae2da208 /lib | |
parent | f9bb8fbe832409893b17f2113d7b35b9ffe91540 (diff) | |
parent | d031472227b44d040698e6dff52dc79028fde854 (diff) | |
download | samba-4283ae489b6e227beba196e8a315a9727f03cc07.tar.gz samba-4283ae489b6e227beba196e8a315a9727f03cc07.tar.bz2 samba-4283ae489b6e227beba196e8a315a9727f03cc07.zip |
Merge branch 'master' of ssh://jra@git.samba.org/data/git/samba
Diffstat (limited to 'lib')
40 files changed, 5206 insertions, 1797 deletions
diff --git a/lib/tdb/Makefile.in b/lib/tdb/Makefile.in index 9915d88264..df1b02be6a 100644 --- a/lib/tdb/Makefile.in +++ b/lib/tdb/Makefile.in @@ -23,7 +23,6 @@ SHLD_FLAGS = @SHLD_FLAGS@ PACKAGE_VERSION = @PACKAGE_VERSION@ PICFLAG = @PICFLAG@ SHLIBEXT = @SHLIBEXT@ -SWIG = swig PYTHON = @PYTHON@ PYTHON_CONFIG = @PYTHON_CONFIG@ PYTHON_BUILD_TARGET = @PYTHON_BUILD_TARGET@ diff --git a/lib/tdb/autogen.sh b/lib/tdb/autogen.sh index 88ac4cfcf7..bf84eeee19 100755 --- a/lib/tdb/autogen.sh +++ b/lib/tdb/autogen.sh @@ -9,8 +9,6 @@ autoheader $IPATHS || exit 1 rm -rf autom4te.cache -swig -O -Wall -python -keyword tdb.i # Ignore errors for now - echo "Now run ./configure and then make." exit 0 diff --git a/lib/tdb/pytdb.c b/lib/tdb/pytdb.c new file mode 100644 index 0000000000..b7087c4bcc --- /dev/null +++ b/lib/tdb/pytdb.c @@ -0,0 +1,517 @@ +/* + Unix SMB/CIFS implementation. + + Swig interface to tdb. + + Copyright (C) 2004-2006 Tim Potter <tpot@samba.org> + Copyright (C) 2007-2008 Jelmer Vernooij <jelmer@samba.org> + + ** NOTE! The following LGPL license applies to the tdb + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. +*/ + +#include <Python.h> +#ifdef HAVE_FSTAT +#undef HAVE_FSTAT +#endif + +/* Include tdb headers */ +#include <stdint.h> +#include <signal.h> +#include <tdb.h> +#include <fcntl.h> +#include <stdbool.h> + +typedef struct { + PyObject_HEAD + TDB_CONTEXT *ctx; + bool closed; +} PyTdbObject; + +PyAPI_DATA(PyTypeObject) PyTdb; + +static void PyErr_SetTDBError(TDB_CONTEXT *tdb) +{ + PyErr_SetObject(PyExc_RuntimeError, + Py_BuildValue("(i,s)", tdb_error(tdb), tdb_errorstr(tdb))); +} + +static TDB_DATA PyString_AsTDB_DATA(PyObject *data) +{ + TDB_DATA ret; + ret.dptr = (unsigned char *)PyString_AsString(data); + ret.dsize = PyString_Size(data); + return ret; +} + +static PyObject *PyString_FromTDB_DATA(TDB_DATA data) +{ + if (data.dptr == NULL && data.dsize == 0) { + return Py_None; + } else { + PyObject *ret = PyString_FromStringAndSize((const char *)data.dptr, + data.dsize); + free(data.dptr); + return ret; + } +} + +#define PyErr_TDB_ERROR_IS_ERR_RAISE(ret, tdb) \ + if (ret != 0) { \ + PyErr_SetTDBError(tdb); \ + return NULL; \ + } + +static PyObject *py_tdb_open(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + char *name; + int hash_size = 0, tdb_flags = TDB_DEFAULT, flags = O_RDWR, mode = 0600; + TDB_CONTEXT *ctx; + PyTdbObject *ret; + const char *kwnames[] = { "name", "hash_size", "tdb_flags", "flags", "mode", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|iiii", (char **)kwnames, &name, &hash_size, &tdb_flags, &flags, &mode)) + return NULL; + + ctx = tdb_open(name, hash_size, tdb_flags, flags, mode); + if (ctx == NULL) { + PyErr_SetFromErrno(PyExc_IOError); + return NULL; + } + + ret = PyObject_New(PyTdbObject, &PyTdb); + ret->ctx = ctx; + ret->closed = false; + return (PyObject *)ret; +} + +static PyObject *obj_transaction_cancel(PyTdbObject *self) +{ + int ret = tdb_transaction_cancel(self->ctx); + PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx); + return Py_None; +} + +static PyObject *obj_transaction_commit(PyTdbObject *self) +{ + int ret = tdb_transaction_commit(self->ctx); + PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx); + return Py_None; +} + +static PyObject *obj_transaction_recover(PyTdbObject *self) +{ + int ret = tdb_transaction_recover(self->ctx); + PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx); + return Py_None; +} + +static PyObject *obj_transaction_start(PyTdbObject *self) +{ + int ret = tdb_transaction_start(self->ctx); + PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx); + return Py_None; +} + +static PyObject *obj_reopen(PyTdbObject *self) +{ + int ret = tdb_reopen(self->ctx); + PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx); + return Py_None; +} + +static PyObject *obj_lockall(PyTdbObject *self) +{ + int ret = tdb_lockall(self->ctx); + PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx); + return Py_None; +} + +static PyObject *obj_unlockall(PyTdbObject *self) +{ + int ret = tdb_unlockall(self->ctx); + PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx); + return Py_None; +} + +static PyObject *obj_lockall_read(PyTdbObject *self) +{ + int ret = tdb_lockall_read(self->ctx); + PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx); + return Py_None; +} + +static PyObject *obj_unlockall_read(PyTdbObject *self) +{ + int ret = tdb_unlockall_read(self->ctx); + PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx); + return Py_None; +} + +static PyObject *obj_close(PyTdbObject *self) +{ + int ret; + if (self->closed) + return Py_None; + ret = tdb_close(self->ctx); + self->closed = true; + PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx); + return Py_None; +} + +static PyObject *obj_get(PyTdbObject *self, PyObject *args) +{ + TDB_DATA key; + PyObject *py_key; + if (!PyArg_ParseTuple(args, "O", &py_key)) + return NULL; + + key = PyString_AsTDB_DATA(py_key); + + return PyString_FromTDB_DATA(tdb_fetch(self->ctx, key)); +} + +static PyObject *obj_append(PyTdbObject *self, PyObject *args) +{ + TDB_DATA key, data; + PyObject *py_key, *py_data; + int ret; + if (!PyArg_ParseTuple(args, "OO", &py_key, &py_data)) + return NULL; + + key = PyString_AsTDB_DATA(py_key); + data = PyString_AsTDB_DATA(py_data); + + ret = tdb_append(self->ctx, key, data); + PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx); + return Py_None; +} + +static PyObject *obj_firstkey(PyTdbObject *self) +{ + return PyString_FromTDB_DATA(tdb_firstkey(self->ctx)); +} + +static PyObject *obj_nextkey(PyTdbObject *self, PyObject *args) +{ + TDB_DATA key; + PyObject *py_key; + if (!PyArg_ParseTuple(args, "O", &py_key)) + return NULL; + + key = PyString_AsTDB_DATA(py_key); + + return PyString_FromTDB_DATA(tdb_nextkey(self->ctx, key)); +} + +static PyObject *obj_delete(PyTdbObject *self, PyObject *args) +{ + TDB_DATA key; + PyObject *py_key; + int ret; + if (!PyArg_ParseTuple(args, "O", &py_key)) + return NULL; + + key = PyString_AsTDB_DATA(py_key); + ret = tdb_delete(self->ctx, key); + PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx); + return Py_None; +} + +static PyObject *obj_has_key(PyTdbObject *self, PyObject *args) +{ + TDB_DATA key; + int ret; + PyObject *py_key; + if (!PyArg_ParseTuple(args, "O", &py_key)) + return NULL; + + key = PyString_AsTDB_DATA(py_key); + ret = tdb_exists(self->ctx, key); + if (ret != TDB_ERR_NOEXIST) { + PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx); + } + + return (ret == TDB_ERR_NOEXIST)?Py_False:Py_True; +} + +static PyObject *obj_store(PyTdbObject *self, PyObject *args) +{ + TDB_DATA key, value; + int ret; + int flag = TDB_REPLACE; + PyObject *py_key, *py_value; + + if (!PyArg_ParseTuple(args, "OO|i", &py_key, &py_value, &flag)) + return NULL; + + key = PyString_AsTDB_DATA(py_key); + value = PyString_AsTDB_DATA(py_value); + + ret = tdb_store(self->ctx, key, value, flag); + PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx); + return Py_None; +} + + +typedef struct { + PyObject_HEAD + TDB_DATA current; + PyTdbObject *iteratee; +} PyTdbIteratorObject; + +static PyObject *tdb_iter_next(PyTdbIteratorObject *self) +{ + TDB_DATA current; + PyObject *ret; + if (self->current.dptr == NULL && self->current.dsize == 0) + return NULL; + current = self->current; + self->current = tdb_nextkey(self->iteratee->ctx, self->current); + ret = PyString_FromTDB_DATA(current); + return ret; +} + +static void tdb_iter_dealloc(PyTdbIteratorObject *self) +{ + Py_DECREF(self->iteratee); + PyObject_Del(self); +} + +PyTypeObject PyTdbIterator = { + .tp_name = "Iterator", + .tp_basicsize = sizeof(PyTdbIteratorObject), + .tp_iternext = (iternextfunc)tdb_iter_next, + .tp_dealloc = (destructor)tdb_iter_dealloc, + .tp_flags = Py_TPFLAGS_DEFAULT, + .tp_iter = PyObject_SelfIter, +}; + +static PyObject *tdb_object_iter(PyTdbObject *self) +{ + PyTdbIteratorObject *ret; + + ret = PyObject_New(PyTdbIteratorObject, &PyTdbIterator); + ret->current = tdb_firstkey(self->ctx); + ret->iteratee = self; + Py_INCREF(self); + return (PyObject *)ret; +} + +static PyObject *obj_clear(PyTdbObject *self) +{ + int ret = tdb_wipe_all(self->ctx); + PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx); + return Py_None; +} + +static PyMethodDef tdb_object_methods[] = { + { "transaction_cancel", (PyCFunction)obj_transaction_cancel, METH_NOARGS, + "S.transaction_cancel() -> None\n" + "Cancel the currently active transaction." }, + { "transaction_commit", (PyCFunction)obj_transaction_commit, METH_NOARGS, + "S.transaction_commit() -> None\n" + "Commit the currently active transaction." }, + { "transaction_recover", (PyCFunction)obj_transaction_recover, METH_NOARGS, + "S.transaction_recover() -> None\n" + "Recover the currently active transaction." }, + { "transaction_start", (PyCFunction)obj_transaction_start, METH_NOARGS, + "S.transaction_start() -> None\n" + "Start a new transaction." }, + { "reopen", (PyCFunction)obj_reopen, METH_NOARGS, "Reopen this file." }, + { "lock_all", (PyCFunction)obj_lockall, METH_NOARGS, NULL }, + { "unlock_all", (PyCFunction)obj_unlockall, METH_NOARGS, NULL }, + { "read_lock_all", (PyCFunction)obj_lockall_read, METH_NOARGS, NULL }, + { "read_unlock_all", (PyCFunction)obj_unlockall_read, METH_NOARGS, NULL }, + { "close", (PyCFunction)obj_close, METH_NOARGS, NULL }, + { "get", (PyCFunction)obj_get, METH_VARARGS, "S.fetch(key) -> value\n" + "Fetch a value." }, + { "append", (PyCFunction)obj_append, METH_VARARGS, "S.append(key, value) -> None\n" + "Append data to an existing key." }, + { "firstkey", (PyCFunction)obj_firstkey, METH_NOARGS, "S.firstkey() -> data\n" + "Return the first key in this database." }, + { "nextkey", (PyCFunction)obj_nextkey, METH_NOARGS, "S.nextkey(key) -> data\n" + "Return the next key in this database." }, + { "delete", (PyCFunction)obj_delete, METH_VARARGS, "S.delete(key) -> None\n" + "Delete an entry." }, + { "has_key", (PyCFunction)obj_has_key, METH_VARARGS, "S.has_key(key) -> None\n" + "Check whether key exists in this database." }, + { "store", (PyCFunction)obj_store, METH_VARARGS, "S.store(key, data, flag=REPLACE) -> None" + "Store data." }, + { "iterkeys", (PyCFunction)tdb_object_iter, METH_NOARGS, "S.iterkeys() -> iterator" }, + { "clear", (PyCFunction)obj_clear, METH_NOARGS, "S.clear() -> None\n" + "Wipe the entire database." }, + { NULL } +}; + +static PyObject *obj_get_hash_size(PyTdbObject *self, void *closure) +{ + return PyInt_FromLong(tdb_hash_size(self->ctx)); +} + +static int obj_set_max_dead(PyTdbObject *self, PyObject *max_dead, void *closure) +{ + if (!PyInt_Check(max_dead)) + return -1; + tdb_set_max_dead(self->ctx, PyInt_AsLong(max_dead)); + return 0; +} + +static PyObject *obj_get_map_size(PyTdbObject *self, void *closure) +{ + return PyInt_FromLong(tdb_map_size(self->ctx)); +} + +static PyObject *obj_get_flags(PyTdbObject *self, void *closure) +{ + return PyInt_FromLong(tdb_get_flags(self->ctx)); +} + +static PyObject *obj_get_filename(PyTdbObject *self, void *closure) +{ + return PyString_FromString(tdb_name(self->ctx)); +} + +static PyGetSetDef tdb_object_getsetters[] = { + { (char *)"hash_size", (getter)obj_get_hash_size, NULL, NULL }, + { (char *)"map_size", (getter)obj_get_map_size, NULL, NULL }, + { (char *)"flags", (getter)obj_get_flags, NULL, NULL }, + { (char *)"max_dead", NULL, (setter)obj_set_max_dead, NULL }, + { (char *)"filename", (getter)obj_get_filename, NULL, (char *)"The filename of this TDB file."}, + { NULL } +}; + +static PyObject *tdb_object_repr(PyTdbObject *self) +{ + return PyString_FromFormat("Tdb('%s')", tdb_name(self->ctx)); +} + +static void tdb_object_dealloc(PyTdbObject *self) +{ + if (!self->closed) + tdb_close(self->ctx); + PyObject_Del(self); +} + +static PyObject *obj_getitem(PyTdbObject *self, PyObject *key) +{ + TDB_DATA tkey, val; + if (!PyString_Check(key)) { + PyErr_SetString(PyExc_TypeError, "Expected string as key"); + return NULL; + } + + tkey.dptr = (unsigned char *)PyString_AsString(key); + tkey.dsize = PyString_Size(key); + + val = tdb_fetch(self->ctx, tkey); + if (val.dptr == NULL) { + PyErr_SetString(PyExc_KeyError, "No such TDB entry"); + return NULL; + } else { + return PyString_FromTDB_DATA(val); + } +} + +static int obj_setitem(PyTdbObject *self, PyObject *key, PyObject *value) +{ + TDB_DATA tkey, tval; + int ret; + if (!PyString_Check(key)) { + PyErr_SetString(PyExc_TypeError, "Expected string as key"); + return -1; + } + + tkey = PyString_AsTDB_DATA(key); + + if (value == NULL) { + ret = tdb_delete(self->ctx, tkey); + } else { + if (!PyString_Check(value)) { + PyErr_SetString(PyExc_TypeError, "Expected string as value"); + return -1; + } + + tval = PyString_AsTDB_DATA(value); + + ret = tdb_store(self->ctx, tkey, tval, TDB_REPLACE); + } + + if (ret != 0) { + PyErr_SetTDBError(self->ctx); + return -1; + } + + return ret; +} + +static PyMappingMethods tdb_object_mapping = { + .mp_subscript = (binaryfunc)obj_getitem, + .mp_ass_subscript = (objobjargproc)obj_setitem, +}; +PyTypeObject PyTdb = { + .tp_name = "Tdb", + .tp_basicsize = sizeof(PyTdbObject), + .tp_methods = tdb_object_methods, + .tp_getset = tdb_object_getsetters, + .tp_new = py_tdb_open, + .tp_doc = "A TDB file", + .tp_repr = (reprfunc)tdb_object_repr, + .tp_dealloc = (destructor)tdb_object_dealloc, + .tp_as_mapping = &tdb_object_mapping, + .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_ITER, + .tp_iter = (getiterfunc)tdb_object_iter, +}; + +static PyMethodDef tdb_methods[] = { + { "open", (PyCFunction)py_tdb_open, METH_VARARGS|METH_KEYWORDS, "open(name, hash_size=0, tdb_flags=TDB_DEFAULT, flags=O_RDWR, mode=0600)\n" + "Open a TDB file." }, + { NULL } +}; + +void inittdb(void) +{ + PyObject *m; + + if (PyType_Ready(&PyTdb) < 0) + return; + + if (PyType_Ready(&PyTdbIterator) < 0) + return; + + m = Py_InitModule3("tdb", tdb_methods, "TDB is a simple key-value database similar to GDBM that supports multiple writers."); + if (m == NULL) + return; + + PyModule_AddObject(m, "REPLACE", PyInt_FromLong(TDB_REPLACE)); + PyModule_AddObject(m, "INSERT", PyInt_FromLong(TDB_INSERT)); + PyModule_AddObject(m, "MODIFY", PyInt_FromLong(TDB_MODIFY)); + + PyModule_AddObject(m, "DEFAULT", PyInt_FromLong(TDB_DEFAULT)); + PyModule_AddObject(m, "CLEAR_IF_FIRST", PyInt_FromLong(TDB_CLEAR_IF_FIRST)); + PyModule_AddObject(m, "INTERNAL", PyInt_FromLong(TDB_INTERNAL)); + PyModule_AddObject(m, "NOLOCK", PyInt_FromLong(TDB_NOLOCK)); + PyModule_AddObject(m, "NOMMAP", PyInt_FromLong(TDB_NOMMAP)); + PyModule_AddObject(m, "CONVERT", PyInt_FromLong(TDB_CONVERT)); + PyModule_AddObject(m, "BIGENDIAN", PyInt_FromLong(TDB_BIGENDIAN)); + PyModule_AddObject(m, "__docformat__", PyString_FromString("restructuredText")); + + Py_INCREF(&PyTdb); + PyModule_AddObject(m, "Tdb", (PyObject *)&PyTdb); + + Py_INCREF(&PyTdbIterator); +} diff --git a/lib/tdb/python.mk b/lib/tdb/python.mk index 12e8217df9..a4e6037993 100644 --- a/lib/tdb/python.mk +++ b/lib/tdb/python.mk @@ -1,10 +1,8 @@ [PYTHON::swig_tdb] -LIBRARY_REALNAME = _tdb.$(SHLIBEXT) +LIBRARY_REALNAME = tdb.$(SHLIBEXT) PUBLIC_DEPENDENCIES = LIBTDB DYNCONFIG -swig_tdb_OBJ_FILES = $(tdbsrcdir)/tdb_wrap.o +swig_tdb_OBJ_FILES = $(tdbsrcdir)/pytdb.o -$(eval $(call python_py_module_template,tdb.py,$(tdbsrcdir)/tdb.py)) - -$(swig_tdb_OBJ_FILES): CFLAGS+=$(CFLAG_NO_UNUSED_MACROS) $(CFLAG_NO_CAST_QUAL) +$(swig_tdb_OBJ_FILES): CFLAGS+=$(CFLAG_NO_CAST_QUAL) diff --git a/lib/tdb/python/tests/simple.py b/lib/tdb/python/tests/simple.py index 7147718c91..d242e665be 100644 --- a/lib/tdb/python/tests/simple.py +++ b/lib/tdb/python/tests/simple.py @@ -73,25 +73,13 @@ class SimpleTdbTests(TestCase): self.tdb.map_size def test_name(self): - self.tdb.name + self.tdb.filename def test_iterator(self): self.tdb["bla"] = "1" self.tdb["brainslug"] = "2" self.assertEquals(["bla", "brainslug"], list(self.tdb)) - def test_items(self): - self.tdb["bla"] = "1" - self.tdb["brainslug"] = "2" - self.assertEquals([("bla", "1"), ("brainslug", "2")], self.tdb.items()) - - def test_iteritems(self): - self.tdb["bloe"] = "2" - self.tdb["bla"] = "25" - i = self.tdb.iteritems() - self.assertEquals(set([("bla", "25"), ("bloe", "2")]), - set([i.next(), i.next()])) - def test_transaction_cancel(self): self.tdb["bloe"] = "2" self.tdb.transaction_start() @@ -112,39 +100,23 @@ class SimpleTdbTests(TestCase): i = iter(self.tdb) self.assertEquals(set(["bloe", "bla"]), set([i.next(), i.next()])) - def test_keys(self): - self.tdb["bloe"] = "2" - self.tdb["bla"] = "25" - self.assertEquals(["bla", "bloe"], self.tdb.keys()) - def test_iterkeys(self): self.tdb["bloe"] = "2" self.tdb["bla"] = "25" i = self.tdb.iterkeys() self.assertEquals(set(["bloe", "bla"]), set([i.next(), i.next()])) - def test_values(self): - self.tdb["bloe"] = "2" - self.tdb["bla"] = "25" - self.assertEquals(["25", "2"], self.tdb.values()) - - def test_itervalues(self): - self.tdb["bloe"] = "2" - self.tdb["bla"] = "25" - i = self.tdb.itervalues() - self.assertEquals(set(["25", "2"]), set([i.next(), i.next()])) - def test_clear(self): self.tdb["bloe"] = "2" self.tdb["bla"] = "25" - self.assertEquals(2, len(self.tdb)) + self.assertEquals(2, len(list(self.tdb))) self.tdb.clear() - self.assertEquals(0, len(self.tdb)) + self.assertEquals(0, len(list(self.tdb))) def test_len(self): - self.assertEquals(0, len(self.tdb)) + self.assertEquals(0, len(list(self.tdb))) self.tdb["entry"] = "value" - self.assertEquals(1, len(self.tdb)) + self.assertEquals(1, len(list(self.tdb))) if __name__ == '__main__': diff --git a/lib/tdb/tdb.i b/lib/tdb/tdb.i deleted file mode 100644 index 4b529913d7..0000000000 --- a/lib/tdb/tdb.i +++ /dev/null @@ -1,328 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - Swig interface to tdb. - - Copyright (C) 2004-2006 Tim Potter <tpot@samba.org> - Copyright (C) 2007 Jelmer Vernooij <jelmer@samba.org> - - ** NOTE! The following LGPL license applies to the tdb - ** library. This does NOT imply that all of Samba is released - ** under the LGPL - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, see <http://www.gnu.org/licenses/>. -*/ - -%define DOCSTRING -"TDB is a simple key-value database similar to GDBM that supports multiple writers." -%enddef - -%module(docstring=DOCSTRING) tdb - -%{ - -/* This symbol is used in both includes.h and Python.h which causes an - annoying compiler warning. */ - -#ifdef HAVE_FSTAT -#undef HAVE_FSTAT -#endif - -/* Include tdb headers */ -#include <stdint.h> -#include <signal.h> -#include <tdb.h> -#include <fcntl.h> - -typedef TDB_CONTEXT tdb; -%} - -/* The tdb functions will crash if a NULL tdb context is passed */ - -%import exception.i -%import stdint.i - -%typemap(check,noblock=1) TDB_CONTEXT* { - if ($1 == NULL) - SWIG_exception(SWIG_ValueError, - "tdb context must be non-NULL"); -} - -/* In and out typemaps for the TDB_DATA structure. This is converted to - and from the Python string type which can contain arbitrary binary - data.. */ - -%typemap(in,noblock=1) TDB_DATA { - if ($input == Py_None) { - $1.dsize = 0; - $1.dptr = NULL; - } else if (!PyString_Check($input)) { - PyErr_SetString(PyExc_TypeError, "string arg expected"); - return NULL; - } else { - $1.dsize = PyString_Size($input); - $1.dptr = (uint8_t *)PyString_AsString($input); - } -} - -%typemap(out,noblock=1) TDB_DATA { - if ($1.dptr == NULL && $1.dsize == 0) { - $result = Py_None; - } else { - $result = PyString_FromStringAndSize((const char *)$1.dptr, $1.dsize); - free($1.dptr); - } -} - -/* Treat a mode_t as an unsigned integer */ -typedef int mode_t; - -/* flags to tdb_store() */ -%constant int REPLACE = TDB_REPLACE; -%constant int INSERT = TDB_INSERT; -%constant int MODIFY = TDB_MODIFY; - -/* flags for tdb_open() */ -%constant int DEFAULT = TDB_DEFAULT; -%constant int CLEAR_IF_FIRST = TDB_CLEAR_IF_FIRST; -%constant int INTERNAL = TDB_INTERNAL; -%constant int NOLOCK = TDB_NOLOCK; -%constant int NOMMAP = TDB_NOMMAP; -%constant int CONVERT = TDB_CONVERT; -%constant int BIGENDIAN = TDB_BIGENDIAN; - -enum TDB_ERROR { - TDB_SUCCESS=0, - TDB_ERR_CORRUPT, - TDB_ERR_IO, - TDB_ERR_LOCK, - TDB_ERR_OOM, - TDB_ERR_EXISTS, - TDB_ERR_NOLOCK, - TDB_ERR_LOCK_TIMEOUT, - TDB_ERR_NOEXIST, - TDB_ERR_EINVAL, - TDB_ERR_RDONLY -}; - -%rename(lock_all) tdb_context::lockall; -%rename(unlock_all) tdb_context::unlockall; - -%rename(read_lock_all) tdb_context::lockall_read; -%rename(read_unlock_all) tdb_context::unlockall_read; - -%typemap(default,noblock=1) int tdb_flags { - $1 = TDB_DEFAULT; -} - -%typemap(default,noblock=1) int flags { - $1 = O_RDWR; -} - -%typemap(default,noblock=1) int hash_size { - $1 = 0; -} - -%typemap(default,noblock=1) mode_t mode { - $1 = 0600; -} - -%typemap(default,noblock=1) int flag { - $1 = TDB_REPLACE; -} - -%rename(Tdb) tdb_context; -%feature("docstring") tdb_context "A TDB file."; -%typemap(out,noblock=1) tdb * { - /* Throw an IOError exception from errno if tdb_open() returns NULL */ - if ($1 == NULL) { - PyErr_SetFromErrno(PyExc_IOError); - SWIG_fail; - } - $result = SWIG_NewPointerObj($1, $1_descriptor, 0); -} - -typedef struct tdb_context { - %extend { - %feature("docstring") tdb "S.__init__(name,hash_size=0,tdb_flags=TDB_DEFAULT,flags=O_RDWR,mode=0600)\n" - "Open a TDB file."; - tdb(const char *name, int hash_size, int tdb_flags, int flags, mode_t mode) { - return tdb_open(name, hash_size, tdb_flags, flags, mode); - } - %feature("docstring") error "S.error() -> int\n" - "Find last error number returned by operation on this TDB."; - enum TDB_ERROR error(); - ~tdb() { tdb_close($self); } - %feature("docstring") close "S.close() -> None\n" - "Close the TDB file."; - int close(); - int append(TDB_DATA key, TDB_DATA new_dbuf); - %feature("docstring") errorstr "S.errorstr() -> errorstring\n" - "Obtain last error message."; - const char *errorstr(); - %rename(get) fetch; - %feature("docstring") fetch "S.fetch(key) -> value\n" - "Fetch a value."; - TDB_DATA fetch(TDB_DATA key); - %feature("docstring") delete "S.delete(key) -> None\n" - "Delete an entry."; - int delete(TDB_DATA key); - %feature("docstring") store "S.store(key, value, flag=TDB_REPLACE) -> None\n" - "Store an entry."; - int store(TDB_DATA key, TDB_DATA dbuf, int flag); - %feature("docstring") exists "S.exists(key) -> bool\n" - "Check whether key exists in this database."; - int exists(TDB_DATA key); - %feature("docstring") firstkey "S.firstkey() -> data\n" - "Return the first key in this database."; - TDB_DATA firstkey(); - %feature("docstring") nextkey "S.nextkey(prev) -> data\n" - "Return the next key in this database."; - TDB_DATA nextkey(TDB_DATA key); - %feature("docstring") lockall "S.lockall() -> bool"; - int lockall(); - %feature("docstring") unlockall "S.unlockall() -> bool"; - int unlockall(); - %feature("docstring") unlockall "S.lockall_read() -> bool"; - int lockall_read(); - %feature("docstring") unlockall "S.unlockall_read() -> bool"; - int unlockall_read(); - %feature("docstring") reopen "S.reopen() -> bool\n" - "Reopen this file."; - int reopen(); - %feature("docstring") transaction_start "S.transaction_start() -> None\n" - "Start a new transaction."; - int transaction_start(); - %feature("docstring") transaction_commit "S.transaction_commit() -> None\n" - "Commit the currently active transaction."; - int transaction_commit(); - %feature("docstring") transaction_cancel "S.transaction_cancel() -> None\n" - "Cancel the currently active transaction."; - int transaction_cancel(); - int transaction_recover(); - %feature("docstring") hash_size "S.hash_size() -> int"; - int hash_size(); - %feature("docstring") map_size "S.map_size() -> int"; - size_t map_size(); - %feature("docstring") get_flags "S.get_flags() -> int"; - int get_flags(); - %feature("docstring") set_max_dead "S.set_max_dead(int) -> None"; - void set_max_dead(int max_dead); - %feature("docstring") name "S.name() -> path\n" \ - "Return filename of this TDB file."; - const char *name(); - } - - %pythoncode { - def __repr__(self): - return "Tdb('%s')" % self.name() - - # Random access to keys, values - def __getitem__(self, key): - result = self.get(key) - if result is None: - raise KeyError, '%s: %s' % (key, self.errorstr()) - return result - - def __setitem__(self, key, item): - if self.store(key, item) == -1: - raise IOError, self.errorstr() - - def __delitem__(self, key): - if not self.exists(key): - raise KeyError, '%s: %s' % (key, self.errorstr()) - self.delete(key) - - def __contains__(self, key): - return self.exists(key) != 0 - - def has_key(self, key): - return self.exists(key) != 0 - - def fetch_uint32(self, key): - data = self.get(key) - if data is None: - return None - import struct - return struct.unpack("<L", data)[0] - - def fetch_int32(self, key): - data = self.get(key) - if data is None: - return None - import struct - return struct.unpack("<l", data)[0] - - # Tdb iterator - class TdbIterator: - def __init__(self, tdb): - self.tdb = tdb - self.key = None - - def __iter__(self): - return self - - def next(self): - if self.key is None: - self.key = self.tdb.firstkey() - if self.key is None: - raise StopIteration - return self.key - else: - self.key = self.tdb.nextkey(self.key) - if self.key is None: - raise StopIteration - return self.key - - def __iter__(self): - return self.TdbIterator(self) - - # Implement other dict functions using TdbIterator - - def keys(self): - return [k for k in iter(self)] - - def values(self): - return [self[k] for k in iter(self)] - - def items(self): - return [(k, self[k]) for k in iter(self)] - - def __len__(self): - return len(self.keys()) - - def clear(self): - for k in iter(self): - del(self[k]) - - def iterkeys(self): - for k in iter(self): - yield k - - def itervalues(self): - for k in iter(self): - yield self[k] - - def iteritems(self): - for k in iter(self): - yield (k, self[k]) - - # TODO: any other missing methods for container types - } -} tdb; - -%pythoncode { -__docformat__ = 'restructuredText' -open = Tdb -} diff --git a/lib/tdb/tdb.mk b/lib/tdb/tdb.mk index fa8db6d34c..0254575039 100644 --- a/lib/tdb/tdb.mk +++ b/lib/tdb/tdb.mk @@ -33,32 +33,26 @@ clean:: rm -f $(TDB_SONAME) $(TDB_SOLIB) libtdb.a libtdb.$(SHLIBEXT) rm -f $(ALL_PROGS) tdb.pc -build-python:: _tdb.$(SHLIBEXT) +build-python:: tdb.$(SHLIBEXT) tdb_wrap.o: $(tdbdir)/tdb_wrap.c $(CC) $(PICFLAG) -c $(tdbdir)/tdb_wrap.c $(CFLAGS) `$(PYTHON_CONFIG) --cflags` -_tdb.$(SHLIBEXT): libtdb.$(SHLIBEXT) tdb_wrap.o +tdb.$(SHLIBEXT): libtdb.$(SHLIBEXT) tdb_wrap.o $(SHLD) $(SHLD_FLAGS) -o $@ tdb_wrap.o -L. -ltdb `$(PYTHON_CONFIG) --ldflags` install:: installdirs installbin installheaders installlibs \ $(PYTHON_INSTALL_TARGET) install-python:: build-python - mkdir -p $(DESTDIR)`$(PYTHON) -c "import distutils.sysconfig; print distutils.sysconfig.get_python_lib(0, prefix='$(prefix)')"` \ - $(DESTDIR)`$(PYTHON) -c "import distutils.sysconfig; print distutils.sysconfig.get_python_lib(1, prefix='$(prefix)')"` - cp $(tdbdir)/tdb.py $(DESTDIR)`$(PYTHON) -c "import distutils.sysconfig; print distutils.sysconfig.get_python_lib(0, prefix='$(prefix)')"` - cp _tdb.$(SHLIBEXT) $(DESTDIR)`$(PYTHON) -c "import distutils.sysconfig; print distutils.sysconfig.get_python_lib(1, prefix='$(prefix)')"` + mkdir -p $(DESTDIR)`$(PYTHON) -c "import distutils.sysconfig; print distutils.sysconfig.get_python_lib(1, prefix='$(prefix)')"` + cp tdb.$(SHLIBEXT) $(DESTDIR)`$(PYTHON) -c "import distutils.sysconfig; print distutils.sysconfig.get_python_lib(1, prefix='$(prefix)')"` check-python:: build-python $(TDB_SONAME) $(LIB_PATH_VAR)=. PYTHONPATH=".:$(tdbdir)" $(PYTHON) $(tdbdir)/python/tests/simple.py -install-swig:: - mkdir -p $(DESTDIR)`$(SWIG) -swiglib` - cp tdb.i $(DESTDIR)`$(SWIG) -swiglib` - clean:: - rm -f _tdb.$(SHLIBEXT) + rm -f tdb.$(SHLIBEXT) installdirs:: mkdir -p $(DESTDIR)$(bindir) diff --git a/lib/tdb/tdb.py b/lib/tdb/tdb.py deleted file mode 100644 index 42129d2091..0000000000 --- a/lib/tdb/tdb.py +++ /dev/null @@ -1,344 +0,0 @@ -# This file was automatically generated by SWIG (http://www.swig.org). -# Version 1.3.36 -# -# Don't modify this file, modify the SWIG interface instead. - -""" -TDB is a simple key-value database similar to GDBM that supports multiple writers. -""" - -import _tdb -import new -new_instancemethod = new.instancemethod -try: - _swig_property = property -except NameError: - pass # Python < 2.2 doesn't have 'property'. -def _swig_setattr_nondynamic(self,class_type,name,value,static=1): - if (name == "thisown"): return self.this.own(value) - if (name == "this"): - if type(value).__name__ == 'PySwigObject': - self.__dict__[name] = value - return - method = class_type.__swig_setmethods__.get(name,None) - if method: return method(self,value) - if (not static) or hasattr(self,name): - self.__dict__[name] = value - else: - raise AttributeError("You cannot add attributes to %s" % self) - -def _swig_setattr(self,class_type,name,value): - return _swig_setattr_nondynamic(self,class_type,name,value,0) - -def _swig_getattr(self,class_type,name): - if (name == "thisown"): return self.this.own() - method = class_type.__swig_getmethods__.get(name,None) - if method: return method(self) - raise AttributeError,name - -def _swig_repr(self): - try: strthis = "proxy of " + self.this.__repr__() - except: strthis = "" - return "<%s.%s; %s >" % (self.__class__.__module__, self.__class__.__name__, strthis,) - -import types -try: - _object = types.ObjectType - _newclass = 1 -except AttributeError: - class _object : pass - _newclass = 0 -del types - - -def _swig_setattr_nondynamic_method(set): - def set_attr(self,name,value): - if (name == "thisown"): return self.this.own(value) - if hasattr(self,name) or (name == "this"): - set(self,name,value) - else: - raise AttributeError("You cannot add attributes to %s" % self) - return set_attr - - -REPLACE = _tdb.REPLACE -INSERT = _tdb.INSERT -MODIFY = _tdb.MODIFY -DEFAULT = _tdb.DEFAULT -CLEAR_IF_FIRST = _tdb.CLEAR_IF_FIRST -INTERNAL = _tdb.INTERNAL -NOLOCK = _tdb.NOLOCK -NOMMAP = _tdb.NOMMAP -CONVERT = _tdb.CONVERT -BIGENDIAN = _tdb.BIGENDIAN -TDB_SUCCESS = _tdb.TDB_SUCCESS -TDB_ERR_CORRUPT = _tdb.TDB_ERR_CORRUPT -TDB_ERR_IO = _tdb.TDB_ERR_IO -TDB_ERR_LOCK = _tdb.TDB_ERR_LOCK -TDB_ERR_OOM = _tdb.TDB_ERR_OOM -TDB_ERR_EXISTS = _tdb.TDB_ERR_EXISTS -TDB_ERR_NOLOCK = _tdb.TDB_ERR_NOLOCK -TDB_ERR_LOCK_TIMEOUT = _tdb.TDB_ERR_LOCK_TIMEOUT -TDB_ERR_NOEXIST = _tdb.TDB_ERR_NOEXIST -TDB_ERR_EINVAL = _tdb.TDB_ERR_EINVAL -TDB_ERR_RDONLY = _tdb.TDB_ERR_RDONLY -class Tdb(object): - """A TDB file.""" - thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') - __repr__ = _swig_repr - def __init__(self, *args, **kwargs): - """ - S.__init__(name,hash_size=0,tdb_flags=TDB_DEFAULT,flags=O_RDWR,mode=0600) - Open a TDB file. - """ - _tdb.Tdb_swiginit(self,_tdb.new_Tdb(*args, **kwargs)) - def error(*args, **kwargs): - """ - S.error() -> int - Find last error number returned by operation on this TDB. - """ - return _tdb.Tdb_error(*args, **kwargs) - - __swig_destroy__ = _tdb.delete_Tdb - def close(*args, **kwargs): - """ - S.close() -> None - Close the TDB file. - """ - return _tdb.Tdb_close(*args, **kwargs) - - def errorstr(*args, **kwargs): - """ - S.errorstr() -> errorstring - Obtain last error message. - """ - return _tdb.Tdb_errorstr(*args, **kwargs) - - def get(*args, **kwargs): - """ - S.fetch(key) -> value - Fetch a value. - """ - return _tdb.Tdb_get(*args, **kwargs) - - def delete(*args, **kwargs): - """ - S.delete(key) -> None - Delete an entry. - """ - return _tdb.Tdb_delete(*args, **kwargs) - - def store(*args, **kwargs): - """ - S.store(key, value, flag=TDB_REPLACE) -> None - Store an entry. - """ - return _tdb.Tdb_store(*args, **kwargs) - - def exists(*args, **kwargs): - """ - S.exists(key) -> bool - Check whether key exists in this database. - """ - return _tdb.Tdb_exists(*args, **kwargs) - - def firstkey(*args, **kwargs): - """ - S.firstkey() -> data - Return the first key in this database. - """ - return _tdb.Tdb_firstkey(*args, **kwargs) - - def nextkey(*args, **kwargs): - """ - S.nextkey(prev) -> data - Return the next key in this database. - """ - return _tdb.Tdb_nextkey(*args, **kwargs) - - def lock_all(*args, **kwargs): - """S.lockall() -> bool""" - return _tdb.Tdb_lock_all(*args, **kwargs) - - def unlock_all(*args, **kwargs): - """S.unlockall() -> bool""" - return _tdb.Tdb_unlock_all(*args, **kwargs) - - def reopen(*args, **kwargs): - """ - S.reopen() -> bool - Reopen this file. - """ - return _tdb.Tdb_reopen(*args, **kwargs) - - def transaction_start(*args, **kwargs): - """ - S.transaction_start() -> None - Start a new transaction. - """ - return _tdb.Tdb_transaction_start(*args, **kwargs) - - def transaction_commit(*args, **kwargs): - """ - S.transaction_commit() -> None - Commit the currently active transaction. - """ - return _tdb.Tdb_transaction_commit(*args, **kwargs) - - def transaction_cancel(*args, **kwargs): - """ - S.transaction_cancel() -> None - Cancel the currently active transaction. - """ - return _tdb.Tdb_transaction_cancel(*args, **kwargs) - - def hash_size(*args, **kwargs): - """S.hash_size() -> int""" - return _tdb.Tdb_hash_size(*args, **kwargs) - - def map_size(*args, **kwargs): - """S.map_size() -> int""" - return _tdb.Tdb_map_size(*args, **kwargs) - - def get_flags(*args, **kwargs): - """S.get_flags() -> int""" - return _tdb.Tdb_get_flags(*args, **kwargs) - - def set_max_dead(*args, **kwargs): - """S.set_max_dead(int) -> None""" - return _tdb.Tdb_set_max_dead(*args, **kwargs) - - def name(*args, **kwargs): - """ - S.name() -> path - Return filename of this TDB file. - """ - return _tdb.Tdb_name(*args, **kwargs) - - def __repr__(self): - return "Tdb('%s')" % self.name() - - - def __getitem__(self, key): - result = self.get(key) - if result is None: - raise KeyError, '%s: %s' % (key, self.errorstr()) - return result - - def __setitem__(self, key, item): - if self.store(key, item) == -1: - raise IOError, self.errorstr() - - def __delitem__(self, key): - if not self.exists(key): - raise KeyError, '%s: %s' % (key, self.errorstr()) - self.delete(key) - - def __contains__(self, key): - return self.exists(key) != 0 - - def has_key(self, key): - return self.exists(key) != 0 - - def fetch_uint32(self, key): - data = self.get(key) - if data is None: - return None - import struct - return struct.unpack("<L", data)[0] - - def fetch_int32(self, key): - data = self.get(key) - if data is None: - return None - import struct - return struct.unpack("<l", data)[0] - - - class TdbIterator: - def __init__(self, tdb): - self.tdb = tdb - self.key = None - - def __iter__(self): - return self - - def next(self): - if self.key is None: - self.key = self.tdb.firstkey() - if self.key is None: - raise StopIteration - return self.key - else: - self.key = self.tdb.nextkey(self.key) - if self.key is None: - raise StopIteration - return self.key - - def __iter__(self): - return self.TdbIterator(self) - - - - def keys(self): - return [k for k in iter(self)] - - def values(self): - return [self[k] for k in iter(self)] - - def items(self): - return [(k, self[k]) for k in iter(self)] - - def __len__(self): - return len(self.keys()) - - def clear(self): - for k in iter(self): - del(self[k]) - - def iterkeys(self): - for k in iter(self): - yield k - - def itervalues(self): - for k in iter(self): - yield self[k] - - def iteritems(self): - for k in iter(self): - yield (k, self[k]) - - - -Tdb.error = new_instancemethod(_tdb.Tdb_error,None,Tdb) -Tdb.close = new_instancemethod(_tdb.Tdb_close,None,Tdb) -Tdb.append = new_instancemethod(_tdb.Tdb_append,None,Tdb) -Tdb.errorstr = new_instancemethod(_tdb.Tdb_errorstr,None,Tdb) -Tdb.get = new_instancemethod(_tdb.Tdb_get,None,Tdb) -Tdb.delete = new_instancemethod(_tdb.Tdb_delete,None,Tdb) -Tdb.store = new_instancemethod(_tdb.Tdb_store,None,Tdb) -Tdb.exists = new_instancemethod(_tdb.Tdb_exists,None,Tdb) -Tdb.firstkey = new_instancemethod(_tdb.Tdb_firstkey,None,Tdb) -Tdb.nextkey = new_instancemethod(_tdb.Tdb_nextkey,None,Tdb) -Tdb.lock_all = new_instancemethod(_tdb.Tdb_lock_all,None,Tdb) -Tdb.unlock_all = new_instancemethod(_tdb.Tdb_unlock_all,None,Tdb) -Tdb.read_lock_all = new_instancemethod(_tdb.Tdb_read_lock_all,None,Tdb) -Tdb.read_unlock_all = new_instancemethod(_tdb.Tdb_read_unlock_all,None,Tdb) -Tdb.reopen = new_instancemethod(_tdb.Tdb_reopen,None,Tdb) -Tdb.transaction_start = new_instancemethod(_tdb.Tdb_transaction_start,None,Tdb) -Tdb.transaction_commit = new_instancemethod(_tdb.Tdb_transaction_commit,None,Tdb) -Tdb.transaction_cancel = new_instancemethod(_tdb.Tdb_transaction_cancel,None,Tdb) -Tdb.transaction_recover = new_instancemethod(_tdb.Tdb_transaction_recover,None,Tdb) -Tdb.hash_size = new_instancemethod(_tdb.Tdb_hash_size,None,Tdb) -Tdb.map_size = new_instancemethod(_tdb.Tdb_map_size,None,Tdb) -Tdb.get_flags = new_instancemethod(_tdb.Tdb_get_flags,None,Tdb) -Tdb.set_max_dead = new_instancemethod(_tdb.Tdb_set_max_dead,None,Tdb) -Tdb.name = new_instancemethod(_tdb.Tdb_name,None,Tdb) -Tdb_swigregister = _tdb.Tdb_swigregister -Tdb_swigregister(Tdb) - -__docformat__ = 'restructuredText' -open = Tdb - - - diff --git a/lib/tevent/Makefile.in b/lib/tevent/Makefile.in new file mode 100644 index 0000000000..9765d35720 --- /dev/null +++ b/lib/tevent/Makefile.in @@ -0,0 +1,81 @@ +#!gmake +# +# Makefile for tdb directory +# + +CC = @CC@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ +includedir = @includedir@ +libdir = @libdir@ +VPATH = @srcdir@:@libreplacedir@ +srcdir = @srcdir@ +builddir = @builddir@ +sharedbuilddir = @sharedbuilddir@ +INSTALLCMD = @INSTALL@ +CPPFLAGS = @CPPFLAGS@ -I$(srcdir)/include -Iinclude -I. +LDFLAGS = @LDFLAGS@ +EXEEXT = @EXEEXT@ +SHLD = @SHLD@ +SHLD_FLAGS = @SHLD_FLAGS@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PICFLAG = @PICFLAG@ +SHLIBEXT = @SHLIBEXT@ +SWIG = swig +PYTHON = @PYTHON@ +PYTHON_CONFIG = @PYTHON_CONFIG@ +PYTHON_BUILD_TARGET = @PYTHON_BUILD_TARGET@ +PYTHON_INSTALL_TARGET = @PYTHON_INSTALL_TARGET@ +PYTHON_CHECK_TARGET = @PYTHON_CHECK_TARGET@ +LIB_PATH_VAR = @LIB_PATH_VAR@ +teventdir = @teventdir@ + +TALLOC_CFLAGS = @TALLOC_CFLAGS@ +TALLOC_LDFLAGS = @TALLOC_CFLAGS@ +TALLOC_LIBS = @TALLOC_LIBS@ + +TEVENT_CFLAGS = @TEVENT_CFLAGS@ +TEVENT_LDFLAGS = @TEVENT_CFLAGS@ +TEVENT_LIBS = @TEVENT_LIBS@ + +CFLAGS = $(CPPFLAGS) $(TALLOC_CFLAGS) $(TEVENT_CFLAGS) @CFLAGS@ +LDFLAGS = $(TALLOC_LDFLAGS) $(TEVENT_LDFLAGS) @LDFLAGS@ +LIBS = $(TALLOC_LIBS) $(TEVENT_LIBS) @LIBS@ + +TEVENT_OBJ = @TEVENT_OBJ@ @LIBREPLACEOBJ@ + +default: all + +include $(teventdir)/tevent.mk +include $(teventdir)/rules.mk + +all:: showflags dirs $(PROGS) $(TEVENT_SOLIB) libtevent.a $(PYTHON_BUILD_TARGET) + +install:: all +$(TEVENT_SOLIB): $(TEVENT_OBJ) + $(SHLD) $(SHLD_FLAGS) $(LDFLAGS) $(LIBS) -o $@ $(TEVENT_OBJ) @SONAMEFLAG@$(TEVENT_SONAME) + +shared-build: all + ${INSTALLCMD} -d $(sharedbuilddir)/lib + ${INSTALLCMD} -m 644 libtevent.a $(sharedbuilddir)/lib + ${INSTALLCMD} -m 755 $(TEVENT_SOLIB) $(sharedbuilddir)/lib + ln -sf $(TEVENT_SOLIB) $(sharedbuilddir)/lib/$(TEVENT_SONAME) + ln -sf $(TEVENT_SOLIB) $(sharedbuilddir)/lib/libtevent.so + ${INSTALLCMD} -d $(sharedbuilddir)/include + ${INSTALLCMD} -m 644 $(srcdir)/tevent.h $(sharedbuilddir)/include + +check: test + +test:: $(PYTHON_CHECK_TARGET) +installcheck:: test install + +clean:: + rm -f *.o *.a */*.o + +distclean:: clean + rm -f config.log config.status include/config.h config.cache + rm -f Makefile + +realdistclean:: distclean + rm -f configure include/config.h.in diff --git a/lib/tevent/autogen.sh b/lib/tevent/autogen.sh new file mode 100755 index 0000000000..fec05f54d4 --- /dev/null +++ b/lib/tevent/autogen.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +rm -rf autom4te.cache +rm -f configure config.h.in + +IPATHS="-I libreplace -I lib/replace -I ../libreplace -I ../replace -I ../../../lib/replace" +autoconf $IPATHS || exit 1 +autoheader $IPATHS || exit 1 + +rm -rf autom4te.cache + +swig -O -Wall -python -keyword events.i # Ignore errors for now + +echo "Now run ./configure and then make." +exit 0 + diff --git a/lib/tevent/build_macros.m4 b/lib/tevent/build_macros.m4 new file mode 100644 index 0000000000..c036668cd1 --- /dev/null +++ b/lib/tevent/build_macros.m4 @@ -0,0 +1,14 @@ +AC_DEFUN(BUILD_WITH_SHARED_BUILD_DIR, + [ AC_ARG_WITH([shared-build-dir], + [AC_HELP_STRING([--with-shared-build-dir=DIR], + [temporary build directory where libraries are installed [$srcdir/sharedbuild]])]) + + sharedbuilddir="$srcdir/sharedbuild" + if test x"$with_shared_build_dir" != x; then + sharedbuilddir=$with_shared_build_dir + CFLAGS="$CFLAGS -I$with_shared_build_dir/include" + LDFLAGS="$LDFLAGS -L$with_shared_build_dir/lib" + fi + AC_SUBST(sharedbuilddir) + ]) + diff --git a/lib/tevent/config.mk b/lib/tevent/config.mk new file mode 100644 index 0000000000..5f9508a44f --- /dev/null +++ b/lib/tevent/config.mk @@ -0,0 +1,59 @@ +############################## +[MODULE::TEVENT_AIO] +PRIVATE_DEPENDENCIES = LIBAIO_LINUX +SUBSYSTEM = LIBTEVENT +INIT_FUNCTION = s4_events_aio_init +############################## + +TEVENT_AIO_OBJ_FILES = $(libteventsrcdir)/tevent_aio.o + +############################## +[MODULE::TEVENT_EPOLL] +SUBSYSTEM = LIBTEVENT +INIT_FUNCTION = s4_events_epoll_init +############################## + +TEVENT_EPOLL_OBJ_FILES = $(libteventsrcdir)/tevent_epoll.o + +############################## +[MODULE::TEVENT_SELECT] +SUBSYSTEM = LIBTEVENT +INIT_FUNCTION = s4_events_select_init +############################## + +TEVENT_SELECT_OBJ_FILES = $(libteventsrcdir)/tevent_select.o + +############################## +[MODULE::TEVENT_STANDARD] +SUBSYSTEM = LIBTEVENT +INIT_FUNCTION = s4_events_standard_init +############################## + +TEVENT_STANDARD_OBJ_FILES = $(libteventsrcdir)/tevent_standard.o + +################################################ +# Start SUBSYSTEM LIBTEVENT +[LIBRARY::LIBTEVENT] +PUBLIC_DEPENDENCIES = LIBTALLOC +OUTPUT_TYPE = MERGED_OBJ +CFLAGS = -I../lib/tevent +# +# End SUBSYSTEM LIBTEVENT +################################################ + +LIBTEVENT_OBJ_FILES = $(addprefix $(libteventsrcdir)/, tevent.o tevent_timed.o tevent_signal.o tevent_debug.o tevent_util.o tevent_s4.o) + +PUBLIC_HEADERS += $(addprefix $(libteventsrcdir)/, tevent.h tevent_internal.h) + +# TODO: Change python stuff to tevent +[PYTHON::swig_events] +LIBRARY_REALNAME = samba/_events.$(SHLIBEXT) +PRIVATE_DEPENDENCIES = LIBTEVENT LIBSAMBA-HOSTCONFIG LIBSAMBA-UTIL + +swig_events_OBJ_FILES = $(libteventsrcdir)/events_wrap.o + +$(eval $(call python_py_module_template,samba/events.py,$(libteventsrcdir)/events.py)) + +$(swig_events_OBJ_FILES): CFLAGS+=$(CFLAG_NO_UNUSED_MACROS) $(CFLAG_NO_CAST_QUAL) + +PC_FILES += $(libteventsrcdir)/tevent.pc diff --git a/lib/tevent/configure.ac b/lib/tevent/configure.ac new file mode 100644 index 0000000000..75719d13b4 --- /dev/null +++ b/lib/tevent/configure.ac @@ -0,0 +1,40 @@ +AC_PREREQ(2.50) +AC_DEFUN([SMB_MODULE_DEFAULT], [echo -n ""]) +AC_DEFUN([SMB_LIBRARY_ENABLE], [echo -n ""]) +AC_DEFUN([SMB_ENABLE], [echo -n ""]) +AC_DEFUN([SMB_EXT_LIB], [echo -n ""]) +AC_INIT(tevent, 1.0.0) +AC_CONFIG_SRCDIR([tevent.c]) +AC_CONFIG_HEADER(config.h) +AC_LIBREPLACE_ALL_CHECKS + +AC_LD_EXPORT_DYNAMIC +AC_LD_SONAMEFLAG +AC_LD_PICFLAG +AC_LD_SHLIBEXT +AC_LIBREPLACE_SHLD +AC_LIBREPLACE_SHLD_FLAGS +AC_LIBREPLACE_RUNTIME_LIB_PATH_VAR + +m4_include(build_macros.m4) +BUILD_WITH_SHARED_BUILD_DIR + +m4_include(pkg.m4) +m4_include(libtalloc.m4) + +m4_include(libtevent.m4) +AC_PATH_PROGS([PYTHON_CONFIG], [python2.6-config python2.5-config python2.4-config python-config]) +AC_PATH_PROGS([PYTHON], [python2.6 python2.5 python2.4 python]) + +PYTHON_BUILD_TARGET="build-python" +PYTHON_INSTALL_TARGET="install-python" +PYTHON_CHECK_TARGET="check-python" +AC_SUBST(PYTHON_BUILD_TARGET) +AC_SUBST(PYTHON_INSTALL_TARGET) +AC_SUBST(PYTHON_CHECK_TARGET) +if test -z "$PYTHON_CONFIG"; then + PYTHON_BUILD_TARGET="" + PYTHON_INSTALL_TARGET="" + PYTHON_CHECK_TARGET="" +fi +AC_OUTPUT(Makefile events.pc) diff --git a/lib/tevent/events.i b/lib/tevent/events.i new file mode 100644 index 0000000000..7a604a9f23 --- /dev/null +++ b/lib/tevent/events.i @@ -0,0 +1,54 @@ +/* + Unix SMB/CIFS implementation. + Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +%module(docstring="Event management.",package="samba.events") events; + +%import "../../lib/talloc/talloc.i"; + +%{ +#include "tevent.h" +typedef struct event_context event; +%} + +typedef struct event_context { + %extend { + %feature("docstring") event "S.__init__()"; + event(TALLOC_CTX *mem_ctx) { return event_context_init(mem_ctx); } + %feature("docstring") loop_once "S.loop_once() -> int"; + int loop_once(void); + %feature("docstring") loop_wait "S.loop_wait() -> int"; + int loop_wait(void); + } +} event; +%talloctype(event); + +%typemap(default,noblock=1) struct event_context * { + $1 = event_context_init(NULL); +} + +%typemap(default,noblock=1) struct event_context * { + $1 = event_context_init(NULL); +} + +struct event_context *event_context_init_byname(TALLOC_CTX *mem_ctx, const char *name); + +%feature("docstring") event_backend_list "event_backend_list() -> list"; +const char **event_backend_list(TALLOC_CTX *mem_ctx); +%feature("docstring") event_set_default_backend "event_set_default_backend(name) -> None"; +%rename(set_default_backend) event_set_default_backend; +void event_set_default_backend(const char *backend); diff --git a/lib/tevent/events.py b/lib/tevent/events.py new file mode 100644 index 0000000000..c15ea8b9e5 --- /dev/null +++ b/lib/tevent/events.py @@ -0,0 +1,94 @@ +# This file was automatically generated by SWIG (http://www.swig.org). +# Version 1.3.36 +# +# Don't modify this file, modify the SWIG interface instead. + +""" +Event management. +""" + +import _events +import new +new_instancemethod = new.instancemethod +try: + _swig_property = property +except NameError: + pass # Python < 2.2 doesn't have 'property'. +def _swig_setattr_nondynamic(self,class_type,name,value,static=1): + if (name == "thisown"): return self.this.own(value) + if (name == "this"): + if type(value).__name__ == 'PySwigObject': + self.__dict__[name] = value + return + method = class_type.__swig_setmethods__.get(name,None) + if method: return method(self,value) + if (not static) or hasattr(self,name): + self.__dict__[name] = value + else: + raise AttributeError("You cannot add attributes to %s" % self) + +def _swig_setattr(self,class_type,name,value): + return _swig_setattr_nondynamic(self,class_type,name,value,0) + +def _swig_getattr(self,class_type,name): + if (name == "thisown"): return self.this.own() + method = class_type.__swig_getmethods__.get(name,None) + if method: return method(self) + raise AttributeError,name + +def _swig_repr(self): + try: strthis = "proxy of " + self.this.__repr__() + except: strthis = "" + return "<%s.%s; %s >" % (self.__class__.__module__, self.__class__.__name__, strthis,) + +import types +try: + _object = types.ObjectType + _newclass = 1 +except AttributeError: + class _object : pass + _newclass = 0 +del types + + +def _swig_setattr_nondynamic_method(set): + def set_attr(self,name,value): + if (name == "thisown"): return self.this.own(value) + if hasattr(self,name) or (name == "this"): + set(self,name,value) + else: + raise AttributeError("You cannot add attributes to %s" % self) + return set_attr + + +class event(object): + thisown = _swig_property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc='The membership flag') + __repr__ = _swig_repr + def __init__(self, *args, **kwargs): + """S.__init__()""" + _events.event_swiginit(self,_events.new_event(*args, **kwargs)) + def loop_once(*args, **kwargs): + """S.loop_once() -> int""" + return _events.event_loop_once(*args, **kwargs) + + def loop_wait(*args, **kwargs): + """S.loop_wait() -> int""" + return _events.event_loop_wait(*args, **kwargs) + + __swig_destroy__ = _events.delete_event +event.loop_once = new_instancemethod(_events.event_loop_once,None,event) +event.loop_wait = new_instancemethod(_events.event_loop_wait,None,event) +event_swigregister = _events.event_swigregister +event_swigregister(event) + +event_context_init_byname = _events.event_context_init_byname + +def event_backend_list(*args): + """event_backend_list() -> list""" + return _events.event_backend_list(*args) + +def set_default_backend(*args, **kwargs): + """event_set_default_backend(name) -> None""" + return _events.set_default_backend(*args, **kwargs) + + diff --git a/lib/tdb/tdb_wrap.c b/lib/tevent/events_wrap.c index e997e88572..b8b3a962bc 100644 --- a/lib/tdb/tdb_wrap.c +++ b/lib/tevent/events_wrap.c @@ -2480,19 +2480,12 @@ SWIG_Python_MustGetPtr(PyObject *obj, swig_type_info *ty, int argnum, int flags) /* -------- TYPES TABLE (BEGIN) -------- */ -#define SWIGTYPE_p_TDB_DATA swig_types[0] +#define SWIGTYPE_p_TALLOC_CTX swig_types[0] #define SWIGTYPE_p_char swig_types[1] -#define SWIGTYPE_p_int swig_types[2] -#define SWIGTYPE_p_long_long swig_types[3] -#define SWIGTYPE_p_short swig_types[4] -#define SWIGTYPE_p_signed_char swig_types[5] -#define SWIGTYPE_p_tdb_context swig_types[6] -#define SWIGTYPE_p_unsigned_char swig_types[7] -#define SWIGTYPE_p_unsigned_int swig_types[8] -#define SWIGTYPE_p_unsigned_long_long swig_types[9] -#define SWIGTYPE_p_unsigned_short swig_types[10] -static swig_type_info *swig_types[12]; -static swig_module_info swig_module = {swig_types, 11, 0, 0, 0, 0}; +#define SWIGTYPE_p_event_context swig_types[2] +#define SWIGTYPE_p_p_char swig_types[3] +static swig_type_info *swig_types[5]; +static swig_module_info swig_module = {swig_types, 4, 0, 0, 0, 0}; #define SWIG_TypeQuery(name) SWIG_TypeQueryModule(&swig_module, &swig_module, name) #define SWIG_MangledTypeQuery(name) SWIG_MangledTypeQueryModule(&swig_module, &swig_module, name) @@ -2518,11 +2511,11 @@ static swig_module_info swig_module = {swig_types, 11, 0, 0, 0, 0}; #define SWIG_TypeQuery SWIG_Python_TypeQuery /*----------------------------------------------- - @(target):= _tdb.so + @(target):= _events.so ------------------------------------------------*/ -#define SWIG_init init_tdb +#define SWIG_init init_events -#define SWIG_name "_tdb" +#define SWIG_name "_events" #define SWIGVERSION 0x010336 #define SWIG_VERSION SWIGVERSION @@ -2532,22 +2525,10 @@ static swig_module_info swig_module = {swig_types, 11, 0, 0, 0, 0}; #define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),(void**)(a)) +#include "tevent.h" +typedef struct event_context event; -/* This symbol is used in both includes.h and Python.h which causes an - annoying compiler warning. */ - -#ifdef HAVE_FSTAT -#undef HAVE_FSTAT -#endif - -/* Include tdb headers */ -#include <stdint.h> -#include <signal.h> -#include <tdb.h> -#include <fcntl.h> - -typedef TDB_CONTEXT tdb; - +SWIGINTERN event *new_event(TALLOC_CTX *mem_ctx){ return event_context_init(mem_ctx); } #define SWIG_From_long PyInt_FromLong @@ -2558,6 +2539,7 @@ SWIG_From_int (int value) return SWIG_From_long (value); } +SWIGINTERN void delete_event(event *self){ talloc_free(self); } SWIGINTERN swig_type_info* SWIG_pchar_descriptor(void) @@ -2626,294 +2608,40 @@ SWIG_AsCharPtrAndSize(PyObject *obj, char** cptr, size_t* psize, int *alloc) - -#include <limits.h> -#if !defined(SWIG_NO_LLONG_MAX) -# if !defined(LLONG_MAX) && defined(__GNUC__) && defined (__LONG_LONG_MAX__) -# define LLONG_MAX __LONG_LONG_MAX__ -# define LLONG_MIN (-LLONG_MAX - 1LL) -# define ULLONG_MAX (LLONG_MAX * 2ULL + 1ULL) -# endif -#endif - - -SWIGINTERN int -SWIG_AsVal_double (PyObject *obj, double *val) -{ - int res = SWIG_TypeError; - if (PyFloat_Check(obj)) { - if (val) *val = PyFloat_AsDouble(obj); - return SWIG_OK; - } else if (PyInt_Check(obj)) { - if (val) *val = PyInt_AsLong(obj); - return SWIG_OK; - } else if (PyLong_Check(obj)) { - double v = PyLong_AsDouble(obj); - if (!PyErr_Occurred()) { - if (val) *val = v; - return SWIG_OK; - } else { - PyErr_Clear(); - } - } -#ifdef SWIG_PYTHON_CAST_MODE - { - int dispatch = 0; - double d = PyFloat_AsDouble(obj); - if (!PyErr_Occurred()) { - if (val) *val = d; - return SWIG_AddCast(SWIG_OK); - } else { - PyErr_Clear(); - } - if (!dispatch) { - long v = PyLong_AsLong(obj); - if (!PyErr_Occurred()) { - if (val) *val = v; - return SWIG_AddCast(SWIG_AddCast(SWIG_OK)); - } else { - PyErr_Clear(); - } - } - } -#endif - return res; -} - - -#include <float.h> - - -#include <math.h> - - -SWIGINTERNINLINE int -SWIG_CanCastAsInteger(double *d, double min, double max) { - double x = *d; - if ((min <= x && x <= max)) { - double fx = floor(x); - double cx = ceil(x); - double rd = ((x - fx) < 0.5) ? fx : cx; /* simple rint */ - if ((errno == EDOM) || (errno == ERANGE)) { - errno = 0; - } else { - double summ, reps, diff; - if (rd < x) { - diff = x - rd; - } else if (rd > x) { - diff = rd - x; - } else { - return 1; - } - summ = rd + x; - reps = diff/summ; - if (reps < 8*DBL_EPSILON) { - *d = rd; - return 1; - } - } - } - return 0; -} - - -SWIGINTERN int -SWIG_AsVal_long (PyObject *obj, long* val) -{ - if (PyInt_Check(obj)) { - if (val) *val = PyInt_AsLong(obj); - return SWIG_OK; - } else if (PyLong_Check(obj)) { - long v = PyLong_AsLong(obj); - if (!PyErr_Occurred()) { - if (val) *val = v; - return SWIG_OK; - } else { - PyErr_Clear(); - } - } -#ifdef SWIG_PYTHON_CAST_MODE - { - int dispatch = 0; - long v = PyInt_AsLong(obj); - if (!PyErr_Occurred()) { - if (val) *val = v; - return SWIG_AddCast(SWIG_OK); - } else { - PyErr_Clear(); - } - if (!dispatch) { - double d; - int res = SWIG_AddCast(SWIG_AsVal_double (obj,&d)); - if (SWIG_IsOK(res) && SWIG_CanCastAsInteger(&d, LONG_MIN, LONG_MAX)) { - if (val) *val = (long)(d); - return res; - } - } - } -#endif - return SWIG_TypeError; -} - - -SWIGINTERN int -SWIG_AsVal_int (PyObject * obj, int *val) -{ - long v; - int res = SWIG_AsVal_long (obj, &v); - if (SWIG_IsOK(res)) { - if ((v < INT_MIN || v > INT_MAX)) { - return SWIG_OverflowError; - } else { - if (val) *val = (int)(v); - } - } - return res; -} - -SWIGINTERN tdb *new_tdb(char const *name,int hash_size,int tdb_flags,int flags,mode_t mode){ - return tdb_open(name, hash_size, tdb_flags, flags, mode); - } -SWIGINTERN void delete_tdb(tdb *self){ tdb_close(self); } - -SWIGINTERNINLINE PyObject * -SWIG_FromCharPtrAndSize(const char* carray, size_t size) -{ - if (carray) { - if (size > INT_MAX) { - swig_type_info* pchar_descriptor = SWIG_pchar_descriptor(); - return pchar_descriptor ? - SWIG_NewPointerObj((char *)(carray), pchar_descriptor, 0) : SWIG_Py_Void(); - } else { - return PyString_FromStringAndSize(carray, (int)(size)); - } - } else { - return SWIG_Py_Void(); - } -} - - -SWIGINTERNINLINE PyObject * -SWIG_FromCharPtr(const char *cptr) -{ - return SWIG_FromCharPtrAndSize(cptr, (cptr ? strlen(cptr) : 0)); -} - - -SWIGINTERNINLINE PyObject* -SWIG_From_unsigned_SS_long (unsigned long value) -{ - return (value > LONG_MAX) ? - PyLong_FromUnsignedLong(value) : PyInt_FromLong((long)(value)); -} - - -SWIGINTERNINLINE PyObject * -SWIG_From_size_t (size_t value) -{ - return SWIG_From_unsigned_SS_long ((unsigned long)(value)); -} - #ifdef __cplusplus extern "C" { #endif -SWIGINTERN PyObject *_wrap_new_Tdb(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { +SWIGINTERN PyObject *_wrap_new_event(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { PyObject *resultobj = 0; - char *arg1 = (char *) 0 ; - int arg2 ; - int arg3 ; - int arg4 ; - mode_t arg5 ; - int res1 ; - char *buf1 = 0 ; - int alloc1 = 0 ; - int val2 ; - int ecode2 = 0 ; - int val3 ; - int ecode3 = 0 ; - int val4 ; - int ecode4 = 0 ; - int val5 ; - int ecode5 = 0 ; - PyObject * obj0 = 0 ; - PyObject * obj1 = 0 ; - PyObject * obj2 = 0 ; - PyObject * obj3 = 0 ; - PyObject * obj4 = 0 ; - char * kwnames[] = { - (char *) "name",(char *) "hash_size",(char *) "tdb_flags",(char *) "flags",(char *) "mode", NULL - }; - tdb *result = 0 ; + TALLOC_CTX *arg1 = (TALLOC_CTX *) 0 ; + event *result = 0 ; - arg2 = 0; - arg3 = TDB_DEFAULT; - arg4 = O_RDWR; - arg5 = 0600; - if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O|OOOO:new_Tdb",kwnames,&obj0,&obj1,&obj2,&obj3,&obj4)) SWIG_fail; - res1 = SWIG_AsCharPtrAndSize(obj0, &buf1, NULL, &alloc1); - if (!SWIG_IsOK(res1)) { - SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "new_Tdb" "', argument " "1"" of type '" "char const *""'"); - } - arg1 = (char *)(buf1); - if (obj1) { - ecode2 = SWIG_AsVal_int(obj1, &val2); - if (!SWIG_IsOK(ecode2)) { - SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "new_Tdb" "', argument " "2"" of type '" "int""'"); - } - arg2 = (int)(val2); - } - if (obj2) { - ecode3 = SWIG_AsVal_int(obj2, &val3); - if (!SWIG_IsOK(ecode3)) { - SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "new_Tdb" "', argument " "3"" of type '" "int""'"); - } - arg3 = (int)(val3); - } - if (obj3) { - ecode4 = SWIG_AsVal_int(obj3, &val4); - if (!SWIG_IsOK(ecode4)) { - SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "new_Tdb" "', argument " "4"" of type '" "int""'"); - } - arg4 = (int)(val4); - } - if (obj4) { - ecode5 = SWIG_AsVal_int(obj4, &val5); - if (!SWIG_IsOK(ecode5)) { - SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "new_Tdb" "', argument " "5"" of type '" "mode_t""'"); - } - arg5 = (mode_t)(val5); - } - result = (tdb *)new_tdb((char const *)arg1,arg2,arg3,arg4,arg5); - /* Throw an IOError exception from errno if tdb_open() returns NULL */ - if (result == NULL) { - PyErr_SetFromErrno(PyExc_IOError); - SWIG_fail; - } - resultobj = SWIG_NewPointerObj(result, SWIGTYPE_p_tdb_context, 0); - if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); + arg1 = NULL; + if (!SWIG_Python_UnpackTuple(args,"new_event",0,0,0)) SWIG_fail; + result = (event *)new_event(arg1); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_event_context, SWIG_POINTER_NEW | 0 ); return resultobj; fail: - if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); return NULL; } -SWIGINTERN PyObject *_wrap_Tdb_error(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { +SWIGINTERN PyObject *_wrap_event_loop_once(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { PyObject *resultobj = 0; - tdb *arg1 = (tdb *) 0 ; + event *arg1 = (event *) 0 ; void *argp1 = 0 ; int res1 = 0 ; PyObject *swig_obj[1] ; - enum TDB_ERROR result; + int result; if (!args) SWIG_fail; swig_obj[0] = args; - res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_tdb_context, 0 | 0 ); + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_event_context, 0 | 0 ); if (!SWIG_IsOK(res1)) { - SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_error" "', argument " "1"" of type '" "tdb *""'"); + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "event_loop_once" "', argument " "1"" of type '" "event *""'"); } - arg1 = (tdb *)(argp1); - result = (enum TDB_ERROR)tdb_error(arg1); + arg1 = (event *)(argp1); + result = (int)event_loop_once(arg1); resultobj = SWIG_From_int((int)(result)); return resultobj; fail: @@ -2921,31 +2649,9 @@ fail: } -SWIGINTERN PyObject *_wrap_delete_Tdb(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { +SWIGINTERN PyObject *_wrap_event_loop_wait(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { PyObject *resultobj = 0; - tdb *arg1 = (tdb *) 0 ; - void *argp1 = 0 ; - int res1 = 0 ; - PyObject *swig_obj[1] ; - - if (!args) SWIG_fail; - swig_obj[0] = args; - res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_tdb_context, SWIG_POINTER_DISOWN | 0 ); - if (!SWIG_IsOK(res1)) { - SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_Tdb" "', argument " "1"" of type '" "tdb *""'"); - } - arg1 = (tdb *)(argp1); - delete_tdb(arg1); - resultobj = SWIG_Py_Void(); - return resultobj; -fail: - return NULL; -} - - -SWIGINTERN PyObject *_wrap_Tdb_close(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { - PyObject *resultobj = 0; - tdb *arg1 = (tdb *) 0 ; + event *arg1 = (event *) 0 ; void *argp1 = 0 ; int res1 = 0 ; PyObject *swig_obj[1] ; @@ -2953,61 +2659,12 @@ SWIGINTERN PyObject *_wrap_Tdb_close(PyObject *SWIGUNUSEDPARM(self), PyObject *a if (!args) SWIG_fail; swig_obj[0] = args; - res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_tdb_context, 0 | 0 ); + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_event_context, 0 | 0 ); if (!SWIG_IsOK(res1)) { - SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_close" "', argument " "1"" of type '" "tdb *""'"); - } - arg1 = (tdb *)(argp1); - result = (int)tdb_close(arg1); - resultobj = SWIG_From_int((int)(result)); - return resultobj; -fail: - return NULL; -} - - -SWIGINTERN PyObject *_wrap_Tdb_append(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { - PyObject *resultobj = 0; - tdb *arg1 = (tdb *) 0 ; - TDB_DATA arg2 ; - TDB_DATA arg3 ; - void *argp1 = 0 ; - int res1 = 0 ; - PyObject * obj0 = 0 ; - PyObject * obj1 = 0 ; - PyObject * obj2 = 0 ; - char * kwnames[] = { - (char *) "self",(char *) "key",(char *) "new_dbuf", NULL - }; - int result; - - if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOO:Tdb_append",kwnames,&obj0,&obj1,&obj2)) SWIG_fail; - res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_tdb_context, 0 | 0 ); - if (!SWIG_IsOK(res1)) { - SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_append" "', argument " "1"" of type '" "tdb *""'"); - } - arg1 = (tdb *)(argp1); - if (obj1 == Py_None) { - (&arg2)->dsize = 0; - (&arg2)->dptr = NULL; - } else if (!PyString_Check(obj1)) { - PyErr_SetString(PyExc_TypeError, "string arg expected"); - return NULL; - } else { - (&arg2)->dsize = PyString_Size(obj1); - (&arg2)->dptr = (uint8_t *)PyString_AsString(obj1); - } - if (obj2 == Py_None) { - (&arg3)->dsize = 0; - (&arg3)->dptr = NULL; - } else if (!PyString_Check(obj2)) { - PyErr_SetString(PyExc_TypeError, "string arg expected"); - return NULL; - } else { - (&arg3)->dsize = PyString_Size(obj2); - (&arg3)->dptr = (uint8_t *)PyString_AsString(obj2); + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "event_loop_wait" "', argument " "1"" of type '" "event *""'"); } - result = (int)tdb_append(arg1,arg2,arg3); + arg1 = (event *)(argp1); + result = (int)event_loop_wait(arg1); resultobj = SWIG_From_int((int)(result)); return resultobj; fail: @@ -3015,749 +2672,149 @@ fail: } -SWIGINTERN PyObject *_wrap_Tdb_errorstr(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { +SWIGINTERN PyObject *_wrap_delete_event(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { PyObject *resultobj = 0; - tdb *arg1 = (tdb *) 0 ; + event *arg1 = (event *) 0 ; void *argp1 = 0 ; int res1 = 0 ; PyObject *swig_obj[1] ; - char *result = 0 ; if (!args) SWIG_fail; swig_obj[0] = args; - res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_tdb_context, 0 | 0 ); - if (!SWIG_IsOK(res1)) { - SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_errorstr" "', argument " "1"" of type '" "tdb *""'"); - } - arg1 = (tdb *)(argp1); - result = (char *)tdb_errorstr(arg1); - resultobj = SWIG_FromCharPtr((const char *)result); - return resultobj; -fail: - return NULL; -} - - -SWIGINTERN PyObject *_wrap_Tdb_get(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { - PyObject *resultobj = 0; - tdb *arg1 = (tdb *) 0 ; - TDB_DATA arg2 ; - void *argp1 = 0 ; - int res1 = 0 ; - PyObject * obj0 = 0 ; - PyObject * obj1 = 0 ; - char * kwnames[] = { - (char *) "self",(char *) "key", NULL - }; - TDB_DATA result; - - if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:Tdb_get",kwnames,&obj0,&obj1)) SWIG_fail; - res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_tdb_context, 0 | 0 ); - if (!SWIG_IsOK(res1)) { - SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_get" "', argument " "1"" of type '" "tdb *""'"); - } - arg1 = (tdb *)(argp1); - if (obj1 == Py_None) { - (&arg2)->dsize = 0; - (&arg2)->dptr = NULL; - } else if (!PyString_Check(obj1)) { - PyErr_SetString(PyExc_TypeError, "string arg expected"); - return NULL; - } else { - (&arg2)->dsize = PyString_Size(obj1); - (&arg2)->dptr = (uint8_t *)PyString_AsString(obj1); - } - result = tdb_fetch(arg1,arg2); - if ((&result)->dptr == NULL && (&result)->dsize == 0) { - resultobj = Py_None; - } else { - resultobj = PyString_FromStringAndSize((const char *)(&result)->dptr, (&result)->dsize); - free((&result)->dptr); - } - return resultobj; -fail: - return NULL; -} - - -SWIGINTERN PyObject *_wrap_Tdb_delete(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { - PyObject *resultobj = 0; - tdb *arg1 = (tdb *) 0 ; - TDB_DATA arg2 ; - void *argp1 = 0 ; - int res1 = 0 ; - PyObject * obj0 = 0 ; - PyObject * obj1 = 0 ; - char * kwnames[] = { - (char *) "self",(char *) "key", NULL - }; - int result; - - if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:Tdb_delete",kwnames,&obj0,&obj1)) SWIG_fail; - res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_tdb_context, 0 | 0 ); + res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_event_context, SWIG_POINTER_DISOWN | 0 ); if (!SWIG_IsOK(res1)) { - SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_delete" "', argument " "1"" of type '" "tdb *""'"); - } - arg1 = (tdb *)(argp1); - if (obj1 == Py_None) { - (&arg2)->dsize = 0; - (&arg2)->dptr = NULL; - } else if (!PyString_Check(obj1)) { - PyErr_SetString(PyExc_TypeError, "string arg expected"); - return NULL; - } else { - (&arg2)->dsize = PyString_Size(obj1); - (&arg2)->dptr = (uint8_t *)PyString_AsString(obj1); - } - result = (int)tdb_delete(arg1,arg2); - resultobj = SWIG_From_int((int)(result)); - return resultobj; -fail: - return NULL; -} - - -SWIGINTERN PyObject *_wrap_Tdb_store(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { - PyObject *resultobj = 0; - tdb *arg1 = (tdb *) 0 ; - TDB_DATA arg2 ; - TDB_DATA arg3 ; - int arg4 ; - void *argp1 = 0 ; - int res1 = 0 ; - int val4 ; - int ecode4 = 0 ; - PyObject * obj0 = 0 ; - PyObject * obj1 = 0 ; - PyObject * obj2 = 0 ; - PyObject * obj3 = 0 ; - char * kwnames[] = { - (char *) "self",(char *) "key",(char *) "dbuf",(char *) "flag", NULL - }; - int result; - - arg4 = TDB_REPLACE; - if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOO|O:Tdb_store",kwnames,&obj0,&obj1,&obj2,&obj3)) SWIG_fail; - res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_tdb_context, 0 | 0 ); - if (!SWIG_IsOK(res1)) { - SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_store" "', argument " "1"" of type '" "tdb *""'"); - } - arg1 = (tdb *)(argp1); - if (obj1 == Py_None) { - (&arg2)->dsize = 0; - (&arg2)->dptr = NULL; - } else if (!PyString_Check(obj1)) { - PyErr_SetString(PyExc_TypeError, "string arg expected"); - return NULL; - } else { - (&arg2)->dsize = PyString_Size(obj1); - (&arg2)->dptr = (uint8_t *)PyString_AsString(obj1); - } - if (obj2 == Py_None) { - (&arg3)->dsize = 0; - (&arg3)->dptr = NULL; - } else if (!PyString_Check(obj2)) { - PyErr_SetString(PyExc_TypeError, "string arg expected"); - return NULL; - } else { - (&arg3)->dsize = PyString_Size(obj2); - (&arg3)->dptr = (uint8_t *)PyString_AsString(obj2); + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_event" "', argument " "1"" of type '" "event *""'"); } - if (obj3) { - ecode4 = SWIG_AsVal_int(obj3, &val4); - if (!SWIG_IsOK(ecode4)) { - SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Tdb_store" "', argument " "4"" of type '" "int""'"); - } - arg4 = (int)(val4); - } - result = (int)tdb_store(arg1,arg2,arg3,arg4); - resultobj = SWIG_From_int((int)(result)); + arg1 = (event *)(argp1); + delete_event(arg1); + resultobj = SWIG_Py_Void(); return resultobj; fail: return NULL; } -SWIGINTERN PyObject *_wrap_Tdb_exists(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { - PyObject *resultobj = 0; - tdb *arg1 = (tdb *) 0 ; - TDB_DATA arg2 ; - void *argp1 = 0 ; - int res1 = 0 ; - PyObject * obj0 = 0 ; - PyObject * obj1 = 0 ; - char * kwnames[] = { - (char *) "self",(char *) "key", NULL - }; - int result; - - if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:Tdb_exists",kwnames,&obj0,&obj1)) SWIG_fail; - res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_tdb_context, 0 | 0 ); - if (!SWIG_IsOK(res1)) { - SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_exists" "', argument " "1"" of type '" "tdb *""'"); - } - arg1 = (tdb *)(argp1); - if (obj1 == Py_None) { - (&arg2)->dsize = 0; - (&arg2)->dptr = NULL; - } else if (!PyString_Check(obj1)) { - PyErr_SetString(PyExc_TypeError, "string arg expected"); - return NULL; - } else { - (&arg2)->dsize = PyString_Size(obj1); - (&arg2)->dptr = (uint8_t *)PyString_AsString(obj1); - } - result = (int)tdb_exists(arg1,arg2); - resultobj = SWIG_From_int((int)(result)); - return resultobj; -fail: - return NULL; +SWIGINTERN PyObject *event_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *obj; + if (!SWIG_Python_UnpackTuple(args,(char*)"swigregister", 1, 1,&obj)) return NULL; + SWIG_TypeNewClientData(SWIGTYPE_p_event_context, SWIG_NewClientData(obj)); + return SWIG_Py_Void(); } - -SWIGINTERN PyObject *_wrap_Tdb_firstkey(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { - PyObject *resultobj = 0; - tdb *arg1 = (tdb *) 0 ; - void *argp1 = 0 ; - int res1 = 0 ; - PyObject *swig_obj[1] ; - TDB_DATA result; - - if (!args) SWIG_fail; - swig_obj[0] = args; - res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_tdb_context, 0 | 0 ); - if (!SWIG_IsOK(res1)) { - SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_firstkey" "', argument " "1"" of type '" "tdb *""'"); - } - arg1 = (tdb *)(argp1); - result = tdb_firstkey(arg1); - if ((&result)->dptr == NULL && (&result)->dsize == 0) { - resultobj = Py_None; - } else { - resultobj = PyString_FromStringAndSize((const char *)(&result)->dptr, (&result)->dsize); - free((&result)->dptr); - } - return resultobj; -fail: - return NULL; +SWIGINTERN PyObject *event_swiginit(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + return SWIG_Python_InitShadowInstance(args); } - -SWIGINTERN PyObject *_wrap_Tdb_nextkey(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { +SWIGINTERN PyObject *_wrap_event_context_init_byname(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { PyObject *resultobj = 0; - tdb *arg1 = (tdb *) 0 ; - TDB_DATA arg2 ; - void *argp1 = 0 ; - int res1 = 0 ; + TALLOC_CTX *arg1 = (TALLOC_CTX *) 0 ; + char *arg2 = (char *) 0 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; PyObject * obj0 = 0 ; - PyObject * obj1 = 0 ; char * kwnames[] = { - (char *) "self",(char *) "key", NULL + (char *) "name", NULL }; - TDB_DATA result; - - if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:Tdb_nextkey",kwnames,&obj0,&obj1)) SWIG_fail; - res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_tdb_context, 0 | 0 ); - if (!SWIG_IsOK(res1)) { - SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_nextkey" "', argument " "1"" of type '" "tdb *""'"); - } - arg1 = (tdb *)(argp1); - if (obj1 == Py_None) { - (&arg2)->dsize = 0; - (&arg2)->dptr = NULL; - } else if (!PyString_Check(obj1)) { - PyErr_SetString(PyExc_TypeError, "string arg expected"); - return NULL; - } else { - (&arg2)->dsize = PyString_Size(obj1); - (&arg2)->dptr = (uint8_t *)PyString_AsString(obj1); - } - result = tdb_nextkey(arg1,arg2); - if ((&result)->dptr == NULL && (&result)->dsize == 0) { - resultobj = Py_None; - } else { - resultobj = PyString_FromStringAndSize((const char *)(&result)->dptr, (&result)->dsize); - free((&result)->dptr); - } - return resultobj; -fail: - return NULL; -} - - -SWIGINTERN PyObject *_wrap_Tdb_lock_all(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { - PyObject *resultobj = 0; - tdb *arg1 = (tdb *) 0 ; - void *argp1 = 0 ; - int res1 = 0 ; - PyObject *swig_obj[1] ; - int result; - - if (!args) SWIG_fail; - swig_obj[0] = args; - res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_tdb_context, 0 | 0 ); - if (!SWIG_IsOK(res1)) { - SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_lock_all" "', argument " "1"" of type '" "tdb *""'"); - } - arg1 = (tdb *)(argp1); - result = (int)tdb_lockall(arg1); - resultobj = SWIG_From_int((int)(result)); - return resultobj; -fail: - return NULL; -} - - -SWIGINTERN PyObject *_wrap_Tdb_unlock_all(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { - PyObject *resultobj = 0; - tdb *arg1 = (tdb *) 0 ; - void *argp1 = 0 ; - int res1 = 0 ; - PyObject *swig_obj[1] ; - int result; - - if (!args) SWIG_fail; - swig_obj[0] = args; - res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_tdb_context, 0 | 0 ); - if (!SWIG_IsOK(res1)) { - SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_unlock_all" "', argument " "1"" of type '" "tdb *""'"); - } - arg1 = (tdb *)(argp1); - result = (int)tdb_unlockall(arg1); - resultobj = SWIG_From_int((int)(result)); - return resultobj; -fail: - return NULL; -} - - -SWIGINTERN PyObject *_wrap_Tdb_read_lock_all(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { - PyObject *resultobj = 0; - tdb *arg1 = (tdb *) 0 ; - void *argp1 = 0 ; - int res1 = 0 ; - PyObject *swig_obj[1] ; - int result; - - if (!args) SWIG_fail; - swig_obj[0] = args; - res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_tdb_context, 0 | 0 ); - if (!SWIG_IsOK(res1)) { - SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_read_lock_all" "', argument " "1"" of type '" "tdb *""'"); - } - arg1 = (tdb *)(argp1); - result = (int)tdb_lockall_read(arg1); - resultobj = SWIG_From_int((int)(result)); - return resultobj; -fail: - return NULL; -} - - -SWIGINTERN PyObject *_wrap_Tdb_read_unlock_all(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { - PyObject *resultobj = 0; - tdb *arg1 = (tdb *) 0 ; - void *argp1 = 0 ; - int res1 = 0 ; - PyObject *swig_obj[1] ; - int result; - - if (!args) SWIG_fail; - swig_obj[0] = args; - res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_tdb_context, 0 | 0 ); - if (!SWIG_IsOK(res1)) { - SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_read_unlock_all" "', argument " "1"" of type '" "tdb *""'"); - } - arg1 = (tdb *)(argp1); - result = (int)tdb_unlockall_read(arg1); - resultobj = SWIG_From_int((int)(result)); - return resultobj; -fail: - return NULL; -} - - -SWIGINTERN PyObject *_wrap_Tdb_reopen(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { - PyObject *resultobj = 0; - tdb *arg1 = (tdb *) 0 ; - void *argp1 = 0 ; - int res1 = 0 ; - PyObject *swig_obj[1] ; - int result; - - if (!args) SWIG_fail; - swig_obj[0] = args; - res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_tdb_context, 0 | 0 ); - if (!SWIG_IsOK(res1)) { - SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_reopen" "', argument " "1"" of type '" "tdb *""'"); - } - arg1 = (tdb *)(argp1); - result = (int)tdb_reopen(arg1); - resultobj = SWIG_From_int((int)(result)); - return resultobj; -fail: - return NULL; -} - - -SWIGINTERN PyObject *_wrap_Tdb_transaction_start(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { - PyObject *resultobj = 0; - tdb *arg1 = (tdb *) 0 ; - void *argp1 = 0 ; - int res1 = 0 ; - PyObject *swig_obj[1] ; - int result; - - if (!args) SWIG_fail; - swig_obj[0] = args; - res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_tdb_context, 0 | 0 ); - if (!SWIG_IsOK(res1)) { - SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_transaction_start" "', argument " "1"" of type '" "tdb *""'"); - } - arg1 = (tdb *)(argp1); - result = (int)tdb_transaction_start(arg1); - resultobj = SWIG_From_int((int)(result)); - return resultobj; -fail: - return NULL; -} - - -SWIGINTERN PyObject *_wrap_Tdb_transaction_commit(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { - PyObject *resultobj = 0; - tdb *arg1 = (tdb *) 0 ; - void *argp1 = 0 ; - int res1 = 0 ; - PyObject *swig_obj[1] ; - int result; - - if (!args) SWIG_fail; - swig_obj[0] = args; - res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_tdb_context, 0 | 0 ); - if (!SWIG_IsOK(res1)) { - SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_transaction_commit" "', argument " "1"" of type '" "tdb *""'"); - } - arg1 = (tdb *)(argp1); - result = (int)tdb_transaction_commit(arg1); - resultobj = SWIG_From_int((int)(result)); - return resultobj; -fail: - return NULL; -} - - -SWIGINTERN PyObject *_wrap_Tdb_transaction_cancel(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { - PyObject *resultobj = 0; - tdb *arg1 = (tdb *) 0 ; - void *argp1 = 0 ; - int res1 = 0 ; - PyObject *swig_obj[1] ; - int result; - - if (!args) SWIG_fail; - swig_obj[0] = args; - res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_tdb_context, 0 | 0 ); - if (!SWIG_IsOK(res1)) { - SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_transaction_cancel" "', argument " "1"" of type '" "tdb *""'"); - } - arg1 = (tdb *)(argp1); - result = (int)tdb_transaction_cancel(arg1); - resultobj = SWIG_From_int((int)(result)); - return resultobj; -fail: - return NULL; -} - - -SWIGINTERN PyObject *_wrap_Tdb_transaction_recover(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { - PyObject *resultobj = 0; - tdb *arg1 = (tdb *) 0 ; - void *argp1 = 0 ; - int res1 = 0 ; - PyObject *swig_obj[1] ; - int result; - - if (!args) SWIG_fail; - swig_obj[0] = args; - res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_tdb_context, 0 | 0 ); - if (!SWIG_IsOK(res1)) { - SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_transaction_recover" "', argument " "1"" of type '" "tdb *""'"); - } - arg1 = (tdb *)(argp1); - result = (int)tdb_transaction_recover(arg1); - resultobj = SWIG_From_int((int)(result)); - return resultobj; -fail: - return NULL; -} - - -SWIGINTERN PyObject *_wrap_Tdb_hash_size(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { - PyObject *resultobj = 0; - tdb *arg1 = (tdb *) 0 ; - void *argp1 = 0 ; - int res1 = 0 ; - PyObject *swig_obj[1] ; - int result; - - if (!args) SWIG_fail; - swig_obj[0] = args; - res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_tdb_context, 0 | 0 ); - if (!SWIG_IsOK(res1)) { - SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_hash_size" "', argument " "1"" of type '" "tdb *""'"); - } - arg1 = (tdb *)(argp1); - result = (int)tdb_hash_size(arg1); - resultobj = SWIG_From_int((int)(result)); + struct event_context *result = 0 ; + + arg1 = NULL; + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O:event_context_init_byname",kwnames,&obj0)) SWIG_fail; + res2 = SWIG_AsCharPtrAndSize(obj0, &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "event_context_init_byname" "', argument " "2"" of type '" "char const *""'"); + } + arg2 = (char *)(buf2); + result = (struct event_context *)event_context_init_byname(arg1,(char const *)arg2); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_event_context, 0 | 0 ); + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); return resultobj; fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); return NULL; } -SWIGINTERN PyObject *_wrap_Tdb_map_size(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { +SWIGINTERN PyObject *_wrap_event_backend_list(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { PyObject *resultobj = 0; - tdb *arg1 = (tdb *) 0 ; - void *argp1 = 0 ; - int res1 = 0 ; - PyObject *swig_obj[1] ; - size_t result; + TALLOC_CTX *arg1 = (TALLOC_CTX *) 0 ; + char **result = 0 ; - if (!args) SWIG_fail; - swig_obj[0] = args; - res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_tdb_context, 0 | 0 ); - if (!SWIG_IsOK(res1)) { - SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_map_size" "', argument " "1"" of type '" "tdb *""'"); - } - arg1 = (tdb *)(argp1); - result = tdb_map_size(arg1); - resultobj = SWIG_From_size_t((size_t)(result)); + arg1 = NULL; + if (!SWIG_Python_UnpackTuple(args,"event_backend_list",0,0,0)) SWIG_fail; + result = (char **)event_backend_list(arg1); + resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_p_char, 0 | 0 ); return resultobj; fail: return NULL; } -SWIGINTERN PyObject *_wrap_Tdb_get_flags(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { +SWIGINTERN PyObject *_wrap_set_default_backend(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { PyObject *resultobj = 0; - tdb *arg1 = (tdb *) 0 ; - void *argp1 = 0 ; - int res1 = 0 ; - PyObject *swig_obj[1] ; - int result; - - if (!args) SWIG_fail; - swig_obj[0] = args; - res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_tdb_context, 0 | 0 ); - if (!SWIG_IsOK(res1)) { - SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_get_flags" "', argument " "1"" of type '" "tdb *""'"); - } - arg1 = (tdb *)(argp1); - result = (int)tdb_get_flags(arg1); - resultobj = SWIG_From_int((int)(result)); - return resultobj; -fail: - return NULL; -} - - -SWIGINTERN PyObject *_wrap_Tdb_set_max_dead(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { - PyObject *resultobj = 0; - tdb *arg1 = (tdb *) 0 ; - int arg2 ; - void *argp1 = 0 ; - int res1 = 0 ; - int val2 ; - int ecode2 = 0 ; + char *arg1 = (char *) 0 ; + int res1 ; + char *buf1 = 0 ; + int alloc1 = 0 ; PyObject * obj0 = 0 ; - PyObject * obj1 = 0 ; char * kwnames[] = { - (char *) "self",(char *) "max_dead", NULL + (char *) "backend", NULL }; - if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:Tdb_set_max_dead",kwnames,&obj0,&obj1)) SWIG_fail; - res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_tdb_context, 0 | 0 ); + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O:set_default_backend",kwnames,&obj0)) SWIG_fail; + res1 = SWIG_AsCharPtrAndSize(obj0, &buf1, NULL, &alloc1); if (!SWIG_IsOK(res1)) { - SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_set_max_dead" "', argument " "1"" of type '" "tdb *""'"); + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "set_default_backend" "', argument " "1"" of type '" "char const *""'"); } - arg1 = (tdb *)(argp1); - ecode2 = SWIG_AsVal_int(obj1, &val2); - if (!SWIG_IsOK(ecode2)) { - SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Tdb_set_max_dead" "', argument " "2"" of type '" "int""'"); - } - arg2 = (int)(val2); - tdb_set_max_dead(arg1,arg2); + arg1 = (char *)(buf1); + event_set_default_backend((char const *)arg1); resultobj = SWIG_Py_Void(); + if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); return resultobj; fail: + if (alloc1 == SWIG_NEWOBJ) free((char*)buf1); return NULL; } -SWIGINTERN PyObject *_wrap_Tdb_name(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { - PyObject *resultobj = 0; - tdb *arg1 = (tdb *) 0 ; - void *argp1 = 0 ; - int res1 = 0 ; - PyObject *swig_obj[1] ; - char *result = 0 ; - - if (!args) SWIG_fail; - swig_obj[0] = args; - res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_tdb_context, 0 | 0 ); - if (!SWIG_IsOK(res1)) { - SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Tdb_name" "', argument " "1"" of type '" "tdb *""'"); - } - arg1 = (tdb *)(argp1); - result = (char *)tdb_name(arg1); - resultobj = SWIG_FromCharPtr((const char *)result); - return resultobj; -fail: - return NULL; -} - - -SWIGINTERN PyObject *Tdb_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { - PyObject *obj; - if (!SWIG_Python_UnpackTuple(args,(char*)"swigregister", 1, 1,&obj)) return NULL; - SWIG_TypeNewClientData(SWIGTYPE_p_tdb_context, SWIG_NewClientData(obj)); - return SWIG_Py_Void(); -} - -SWIGINTERN PyObject *Tdb_swiginit(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { - return SWIG_Python_InitShadowInstance(args); -} - static PyMethodDef SwigMethods[] = { - { (char *)"new_Tdb", (PyCFunction) _wrap_new_Tdb, METH_VARARGS | METH_KEYWORDS, (char *)"\n" - "S.__init__(name,hash_size=0,tdb_flags=TDB_DEFAULT,flags=O_RDWR,mode=0600)\n" - "Open a TDB file.\n" - ""}, - { (char *)"Tdb_error", (PyCFunction)_wrap_Tdb_error, METH_O, (char *)"\n" - "S.error() -> int\n" - "Find last error number returned by operation on this TDB.\n" - ""}, - { (char *)"delete_Tdb", (PyCFunction)_wrap_delete_Tdb, METH_O, NULL}, - { (char *)"Tdb_close", (PyCFunction)_wrap_Tdb_close, METH_O, (char *)"\n" - "S.close() -> None\n" - "Close the TDB file.\n" - ""}, - { (char *)"Tdb_append", (PyCFunction) _wrap_Tdb_append, METH_VARARGS | METH_KEYWORDS, NULL}, - { (char *)"Tdb_errorstr", (PyCFunction)_wrap_Tdb_errorstr, METH_O, (char *)"\n" - "S.errorstr() -> errorstring\n" - "Obtain last error message.\n" - ""}, - { (char *)"Tdb_get", (PyCFunction) _wrap_Tdb_get, METH_VARARGS | METH_KEYWORDS, (char *)"\n" - "S.fetch(key) -> value\n" - "Fetch a value.\n" - ""}, - { (char *)"Tdb_delete", (PyCFunction) _wrap_Tdb_delete, METH_VARARGS | METH_KEYWORDS, (char *)"\n" - "S.delete(key) -> None\n" - "Delete an entry.\n" - ""}, - { (char *)"Tdb_store", (PyCFunction) _wrap_Tdb_store, METH_VARARGS | METH_KEYWORDS, (char *)"\n" - "S.store(key, value, flag=TDB_REPLACE) -> None\n" - "Store an entry.\n" - ""}, - { (char *)"Tdb_exists", (PyCFunction) _wrap_Tdb_exists, METH_VARARGS | METH_KEYWORDS, (char *)"\n" - "S.exists(key) -> bool\n" - "Check whether key exists in this database.\n" - ""}, - { (char *)"Tdb_firstkey", (PyCFunction)_wrap_Tdb_firstkey, METH_O, (char *)"\n" - "S.firstkey() -> data\n" - "Return the first key in this database.\n" - ""}, - { (char *)"Tdb_nextkey", (PyCFunction) _wrap_Tdb_nextkey, METH_VARARGS | METH_KEYWORDS, (char *)"\n" - "S.nextkey(prev) -> data\n" - "Return the next key in this database.\n" - ""}, - { (char *)"Tdb_lock_all", (PyCFunction)_wrap_Tdb_lock_all, METH_O, (char *)"S.lockall() -> bool"}, - { (char *)"Tdb_unlock_all", (PyCFunction)_wrap_Tdb_unlock_all, METH_O, (char *)"S.unlockall() -> bool"}, - { (char *)"Tdb_read_lock_all", (PyCFunction)_wrap_Tdb_read_lock_all, METH_O, NULL}, - { (char *)"Tdb_read_unlock_all", (PyCFunction)_wrap_Tdb_read_unlock_all, METH_O, NULL}, - { (char *)"Tdb_reopen", (PyCFunction)_wrap_Tdb_reopen, METH_O, (char *)"\n" - "S.reopen() -> bool\n" - "Reopen this file.\n" - ""}, - { (char *)"Tdb_transaction_start", (PyCFunction)_wrap_Tdb_transaction_start, METH_O, (char *)"\n" - "S.transaction_start() -> None\n" - "Start a new transaction.\n" - ""}, - { (char *)"Tdb_transaction_commit", (PyCFunction)_wrap_Tdb_transaction_commit, METH_O, (char *)"\n" - "S.transaction_commit() -> None\n" - "Commit the currently active transaction.\n" - ""}, - { (char *)"Tdb_transaction_cancel", (PyCFunction)_wrap_Tdb_transaction_cancel, METH_O, (char *)"\n" - "S.transaction_cancel() -> None\n" - "Cancel the currently active transaction.\n" - ""}, - { (char *)"Tdb_transaction_recover", (PyCFunction)_wrap_Tdb_transaction_recover, METH_O, NULL}, - { (char *)"Tdb_hash_size", (PyCFunction)_wrap_Tdb_hash_size, METH_O, (char *)"S.hash_size() -> int"}, - { (char *)"Tdb_map_size", (PyCFunction)_wrap_Tdb_map_size, METH_O, (char *)"S.map_size() -> int"}, - { (char *)"Tdb_get_flags", (PyCFunction)_wrap_Tdb_get_flags, METH_O, (char *)"S.get_flags() -> int"}, - { (char *)"Tdb_set_max_dead", (PyCFunction) _wrap_Tdb_set_max_dead, METH_VARARGS | METH_KEYWORDS, (char *)"S.set_max_dead(int) -> None"}, - { (char *)"Tdb_name", (PyCFunction)_wrap_Tdb_name, METH_O, (char *)"\n" - "S.name() -> path\n" - "Return filename of this TDB file.\n" - ""}, - { (char *)"Tdb_swigregister", Tdb_swigregister, METH_VARARGS, NULL}, - { (char *)"Tdb_swiginit", Tdb_swiginit, METH_VARARGS, NULL}, + { (char *)"new_event", (PyCFunction)_wrap_new_event, METH_NOARGS, (char *)"S.__init__()"}, + { (char *)"event_loop_once", (PyCFunction)_wrap_event_loop_once, METH_O, (char *)"S.loop_once() -> int"}, + { (char *)"event_loop_wait", (PyCFunction)_wrap_event_loop_wait, METH_O, (char *)"S.loop_wait() -> int"}, + { (char *)"delete_event", (PyCFunction)_wrap_delete_event, METH_O, NULL}, + { (char *)"event_swigregister", event_swigregister, METH_VARARGS, NULL}, + { (char *)"event_swiginit", event_swiginit, METH_VARARGS, NULL}, + { (char *)"event_context_init_byname", (PyCFunction) _wrap_event_context_init_byname, METH_VARARGS | METH_KEYWORDS, NULL}, + { (char *)"event_backend_list", (PyCFunction)_wrap_event_backend_list, METH_NOARGS, (char *)"event_backend_list() -> list"}, + { (char *)"set_default_backend", (PyCFunction) _wrap_set_default_backend, METH_VARARGS | METH_KEYWORDS, (char *)"event_set_default_backend(name) -> None"}, { NULL, NULL, 0, NULL } }; /* -------- TYPE CONVERSION AND EQUIVALENCE RULES (BEGIN) -------- */ -static swig_type_info _swigt__p_TDB_DATA = {"_p_TDB_DATA", "TDB_DATA *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_TALLOC_CTX = {"_p_TALLOC_CTX", "TALLOC_CTX *", 0, 0, (void*)0, 0}; static swig_type_info _swigt__p_char = {"_p_char", "char *", 0, 0, (void*)0, 0}; -static swig_type_info _swigt__p_int = {"_p_int", "intptr_t *|int *|int_least32_t *|int_fast32_t *|int32_t *|int_fast16_t *|mode_t *", 0, 0, (void*)0, 0}; -static swig_type_info _swigt__p_long_long = {"_p_long_long", "int_least64_t *|int_fast64_t *|int64_t *|long long *|intmax_t *", 0, 0, (void*)0, 0}; -static swig_type_info _swigt__p_short = {"_p_short", "short *|int_least16_t *|int16_t *", 0, 0, (void*)0, 0}; -static swig_type_info _swigt__p_signed_char = {"_p_signed_char", "signed char *|int_least8_t *|int_fast8_t *|int8_t *", 0, 0, (void*)0, 0}; -static swig_type_info _swigt__p_tdb_context = {"_p_tdb_context", "struct tdb_context *|tdb *", 0, 0, (void*)0, 0}; -static swig_type_info _swigt__p_unsigned_char = {"_p_unsigned_char", "unsigned char *|uint_least8_t *|uint_fast8_t *|uint8_t *", 0, 0, (void*)0, 0}; -static swig_type_info _swigt__p_unsigned_int = {"_p_unsigned_int", "uintptr_t *|uint_least32_t *|uint_fast32_t *|uint32_t *|unsigned int *|uint_fast16_t *", 0, 0, (void*)0, 0}; -static swig_type_info _swigt__p_unsigned_long_long = {"_p_unsigned_long_long", "uint_least64_t *|uint_fast64_t *|uint64_t *|unsigned long long *|uintmax_t *", 0, 0, (void*)0, 0}; -static swig_type_info _swigt__p_unsigned_short = {"_p_unsigned_short", "unsigned short *|uint_least16_t *|uint16_t *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_event_context = {"_p_event_context", "struct event_context *|event *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_p_char = {"_p_p_char", "char **", 0, 0, (void*)0, 0}; static swig_type_info *swig_type_initial[] = { - &_swigt__p_TDB_DATA, + &_swigt__p_TALLOC_CTX, &_swigt__p_char, - &_swigt__p_int, - &_swigt__p_long_long, - &_swigt__p_short, - &_swigt__p_signed_char, - &_swigt__p_tdb_context, - &_swigt__p_unsigned_char, - &_swigt__p_unsigned_int, - &_swigt__p_unsigned_long_long, - &_swigt__p_unsigned_short, + &_swigt__p_event_context, + &_swigt__p_p_char, }; -static swig_cast_info _swigc__p_TDB_DATA[] = { {&_swigt__p_TDB_DATA, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_TALLOC_CTX[] = { {&_swigt__p_TALLOC_CTX, 0, 0, 0},{0, 0, 0, 0}}; static swig_cast_info _swigc__p_char[] = { {&_swigt__p_char, 0, 0, 0},{0, 0, 0, 0}}; -static swig_cast_info _swigc__p_int[] = { {&_swigt__p_int, 0, 0, 0},{0, 0, 0, 0}}; -static swig_cast_info _swigc__p_long_long[] = { {&_swigt__p_long_long, 0, 0, 0},{0, 0, 0, 0}}; -static swig_cast_info _swigc__p_short[] = { {&_swigt__p_short, 0, 0, 0},{0, 0, 0, 0}}; -static swig_cast_info _swigc__p_signed_char[] = { {&_swigt__p_signed_char, 0, 0, 0},{0, 0, 0, 0}}; -static swig_cast_info _swigc__p_tdb_context[] = { {&_swigt__p_tdb_context, 0, 0, 0},{0, 0, 0, 0}}; -static swig_cast_info _swigc__p_unsigned_char[] = { {&_swigt__p_unsigned_char, 0, 0, 0},{0, 0, 0, 0}}; -static swig_cast_info _swigc__p_unsigned_int[] = { {&_swigt__p_unsigned_int, 0, 0, 0},{0, 0, 0, 0}}; -static swig_cast_info _swigc__p_unsigned_long_long[] = { {&_swigt__p_unsigned_long_long, 0, 0, 0},{0, 0, 0, 0}}; -static swig_cast_info _swigc__p_unsigned_short[] = { {&_swigt__p_unsigned_short, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_event_context[] = { {&_swigt__p_event_context, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_p_char[] = { {&_swigt__p_p_char, 0, 0, 0},{0, 0, 0, 0}}; static swig_cast_info *swig_cast_initial[] = { - _swigc__p_TDB_DATA, + _swigc__p_TALLOC_CTX, _swigc__p_char, - _swigc__p_int, - _swigc__p_long_long, - _swigc__p_short, - _swigc__p_signed_char, - _swigc__p_tdb_context, - _swigc__p_unsigned_char, - _swigc__p_unsigned_int, - _swigc__p_unsigned_long_long, - _swigc__p_unsigned_short, + _swigc__p_event_context, + _swigc__p_p_char, }; @@ -4287,26 +3344,5 @@ SWIGEXPORT void SWIG_init(void) { SWIG_InstallConstants(d,swig_const_table); - SWIG_Python_SetConstant(d, "REPLACE",SWIG_From_int((int)(TDB_REPLACE))); - SWIG_Python_SetConstant(d, "INSERT",SWIG_From_int((int)(TDB_INSERT))); - SWIG_Python_SetConstant(d, "MODIFY",SWIG_From_int((int)(TDB_MODIFY))); - SWIG_Python_SetConstant(d, "DEFAULT",SWIG_From_int((int)(TDB_DEFAULT))); - SWIG_Python_SetConstant(d, "CLEAR_IF_FIRST",SWIG_From_int((int)(TDB_CLEAR_IF_FIRST))); - SWIG_Python_SetConstant(d, "INTERNAL",SWIG_From_int((int)(TDB_INTERNAL))); - SWIG_Python_SetConstant(d, "NOLOCK",SWIG_From_int((int)(TDB_NOLOCK))); - SWIG_Python_SetConstant(d, "NOMMAP",SWIG_From_int((int)(TDB_NOMMAP))); - SWIG_Python_SetConstant(d, "CONVERT",SWIG_From_int((int)(TDB_CONVERT))); - SWIG_Python_SetConstant(d, "BIGENDIAN",SWIG_From_int((int)(TDB_BIGENDIAN))); - SWIG_Python_SetConstant(d, "TDB_SUCCESS",SWIG_From_int((int)(TDB_SUCCESS))); - SWIG_Python_SetConstant(d, "TDB_ERR_CORRUPT",SWIG_From_int((int)(TDB_ERR_CORRUPT))); - SWIG_Python_SetConstant(d, "TDB_ERR_IO",SWIG_From_int((int)(TDB_ERR_IO))); - SWIG_Python_SetConstant(d, "TDB_ERR_LOCK",SWIG_From_int((int)(TDB_ERR_LOCK))); - SWIG_Python_SetConstant(d, "TDB_ERR_OOM",SWIG_From_int((int)(TDB_ERR_OOM))); - SWIG_Python_SetConstant(d, "TDB_ERR_EXISTS",SWIG_From_int((int)(TDB_ERR_EXISTS))); - SWIG_Python_SetConstant(d, "TDB_ERR_NOLOCK",SWIG_From_int((int)(TDB_ERR_NOLOCK))); - SWIG_Python_SetConstant(d, "TDB_ERR_LOCK_TIMEOUT",SWIG_From_int((int)(TDB_ERR_LOCK_TIMEOUT))); - SWIG_Python_SetConstant(d, "TDB_ERR_NOEXIST",SWIG_From_int((int)(TDB_ERR_NOEXIST))); - SWIG_Python_SetConstant(d, "TDB_ERR_EINVAL",SWIG_From_int((int)(TDB_ERR_EINVAL))); - SWIG_Python_SetConstant(d, "TDB_ERR_RDONLY",SWIG_From_int((int)(TDB_ERR_RDONLY))); } diff --git a/lib/tevent/libtalloc.m4 b/lib/tevent/libtalloc.m4 new file mode 100644 index 0000000000..a4c5b8a9d9 --- /dev/null +++ b/lib/tevent/libtalloc.m4 @@ -0,0 +1,7 @@ +AC_SUBST(TALLOC_OBJ) +AC_SUBST(TALLOC_CFLAGS) +AC_SUBST(TALLOC_LIBS) + +AC_CHECK_HEADER(talloc.h, + [AC_CHECK_LIB(talloc, talloc_init, [TALLOC_LIBS="-ltalloc"]) ], + [PKG_CHECK_MODULES(TALLOC, talloc)]) diff --git a/lib/tevent/libtevent.m4 b/lib/tevent/libtevent.m4 new file mode 100644 index 0000000000..30105d9bef --- /dev/null +++ b/lib/tevent/libtevent.m4 @@ -0,0 +1,51 @@ +dnl find the tevent sources. This is meant to work both for +dnl standalone builds, and builds of packages using libtevent +if test x"$teventdir" = "x"; then + teventdir="" + teventpaths="$srcdir $srcdir/../lib/tevent $srcdir/tevent $srcdir/../tevent" + for d in $teventpaths; do + if test -f "$d/tevent.c"; then + teventdir="$d" + AC_SUBST(teventdir) + break; + fi + done + if test x"$teventdir" = "x"; then + AC_MSG_ERROR([cannot find libtevent source in $teventpaths]) + fi +fi + +TEVENT_OBJ="tevent.o tevent_select.o tevent_signal.o tevent_timed.o tevent_standard.o tevent_debug.o tevent_util.o" +AC_LIBREPLACE_NETWORK_CHECKS + +SMB_ENABLE(TEVENT_EPOLL, NO) +SMB_ENABLE(TEVENT_AIO, NO) +AC_CHECK_HEADERS(sys/epoll.h) +AC_CHECK_FUNCS(epoll_create) +if test x"$ac_cv_header_sys_epoll_h" = x"yes" -a x"$ac_cv_func_epoll_create" = x"yes"; then + TEVENT_OBJ="$TEVENT_OBJ tevent_epoll.o" + SMB_ENABLE(TEVENT_EPOLL,YES) + AC_DEFINE(HAVE_EPOLL, 1, [Whether epoll available]) + #TODO: remove HAVE_EVENTS_EPOLL and use HAVE_EPOLL + AC_DEFINE(HAVE_EVENTS_EPOLL, 1, [Whether epoll available]) + + # check for native Linux AIO interface + AC_CHECK_HEADERS(libaio.h) + AC_CHECK_LIB_EXT(aio, AIO_LIBS, io_getevents) + if test x"$ac_cv_header_libaio_h" = x"yes" -a x"$ac_cv_lib_ext_aio_io_getevents" = x"yes";then + TEVENT_OBJ="$TEVENT_OBJ tevent_aio.o" + SMB_ENABLE(TEVENT_AIO,YES) + AC_DEFINE(HAVE_LINUX_AIO, 1, [Whether Linux AIO is available]) + fi +fi + +AC_SUBST(TEVENT_OBJ) +SMB_EXT_LIB(LIBAIO_LINUX, $AIO_LIBS) + +TEVENT_CFLAGS="-I$teventdir" +AC_SUBST(TEVENT_CFLAGS) + +TEVENT_LIBS="$AIO_LIBS" +AC_SUBST(TEVENT_LIBS) + + diff --git a/lib/tevent/pkg.m4 b/lib/tevent/pkg.m4 new file mode 100644 index 0000000000..a8b3d06c81 --- /dev/null +++ b/lib/tevent/pkg.m4 @@ -0,0 +1,156 @@ +# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- +# +# Copyright © 2004 Scott James Remnant <scott@netsplit.com>. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see <http://www.gnu.org/licenses/>. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# PKG_PROG_PKG_CONFIG([MIN-VERSION]) +# ---------------------------------- +AC_DEFUN([PKG_PROG_PKG_CONFIG], +[m4_pattern_forbid([^_?PKG_[A-Z_]+$]) +m4_pattern_allow([^PKG_CONFIG(_PATH)?$]) +AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])dnl +if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then + AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) +fi +if test -n "$PKG_CONFIG"; then + _pkg_min_version=m4_default([$1], [0.9.0]) + AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) + if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + PKG_CONFIG="" + fi + +fi[]dnl +])# PKG_PROG_PKG_CONFIG + +# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +# +# Check to see whether a particular set of modules exists. Similar +# to PKG_CHECK_MODULES(), but does not set variables or print errors. +# +# +# Similar to PKG_CHECK_MODULES, make sure that the first instance of +# this or PKG_CHECK_MODULES is called, or make sure to call +# PKG_CHECK_EXISTS manually +# -------------------------------------------------------------- +AC_DEFUN([PKG_CHECK_EXISTS], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +if test -n "$PKG_CONFIG" && \ + AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then + m4_ifval([$2], [$2], [:]) +m4_ifvaln([$3], [else + $3])dnl +fi]) + + +# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) +# --------------------------------------------- +m4_define([_PKG_CONFIG], +[if test -n "$PKG_CONFIG"; then + if test -n "$$1"; then + pkg_cv_[]$1="$$1" + else + PKG_CHECK_EXISTS([$3], + [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`], + [pkg_failed=yes]) + fi +else + pkg_failed=untried +fi[]dnl +])# _PKG_CONFIG + +# _PKG_SHORT_ERRORS_SUPPORTED +# ----------------------------- +AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG]) +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi[]dnl +])# _PKG_SHORT_ERRORS_SUPPORTED + + +# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], +# [ACTION-IF-NOT-FOUND]) +# +# +# Note that if there is a possibility the first call to +# PKG_CHECK_MODULES might not happen, you should be sure to include an +# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac +# +# +# -------------------------------------------------------------- +AC_DEFUN([PKG_CHECK_MODULES], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl +AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl + +pkg_failed=no +AC_MSG_CHECKING([for $1]) + +_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) +_PKG_CONFIG([$1][_LIBS], [libs], [$2]) + +m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS +and $1[]_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details.]) + +if test $pkg_failed = yes; then + _PKG_SHORT_ERRORS_SUPPORTED + if test $_pkg_short_errors_supported = yes; then + $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "$2"` + else + $1[]_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$2"` + fi + # Put the nasty error message in config.log where it belongs + echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD + + ifelse([$4], , [AC_MSG_ERROR(dnl +[Package requirements ($2) were not met: + +$$1_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +_PKG_TEXT +])], + [AC_MSG_RESULT([no]) + $4]) +elif test $pkg_failed = untried; then + ifelse([$4], , [AC_MSG_FAILURE(dnl +[The pkg-config script could not be found or is too old. Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +_PKG_TEXT + +To get pkg-config, see <http://www.freedesktop.org/software/pkgconfig>.])], + [$4]) +else + $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS + $1[]_LIBS=$pkg_cv_[]$1[]_LIBS + AC_MSG_RESULT([yes]) + ifelse([$3], , :, [$3]) +fi[]dnl +])# PKG_CHECK_MODULES diff --git a/lib/tevent/rules.mk b/lib/tevent/rules.mk new file mode 100644 index 0000000000..cfe548039b --- /dev/null +++ b/lib/tevent/rules.mk @@ -0,0 +1,21 @@ +.SUFFIXES: .i _wrap.c + +.i_wrap.c: + $(SWIG) -O -Wall -python -keyword $< + +showflags:: + @echo 'libevents will be compiled with flags:' + @echo ' CFLAGS = $(CFLAGS)' + @echo ' CPPFLAGS = $(CPPFLAGS)' + @echo ' LDFLAGS = $(LDFLAGS)' + @echo ' LIBS = $(LIBS)' + +.SUFFIXES: .c .o + +.c.o: + @echo Compiling $*.c + @mkdir -p `dirname $@` + @$(CC) $(PICFLAG) $(CFLAGS) -c $< -o $@ + +distclean:: + rm -f *~ */*~ diff --git a/lib/tevent/tests.py b/lib/tevent/tests.py new file mode 100644 index 0000000000..006426207e --- /dev/null +++ b/lib/tevent/tests.py @@ -0,0 +1,31 @@ +#!/usr/bin/python + +# Unix SMB/CIFS implementation. +# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +from samba import events +import unittest + +# Just test the bindings are there and that calling them doesn't crash +# anything. + +class EventTestCase(unittest.TestCase): + def test_create(self): + self.assertTrue(events.event() is not None) + + def test_loop_wait(self): + self.assertEquals(0, events.event().loop_wait()) diff --git a/lib/tevent/testsuite.c b/lib/tevent/testsuite.c new file mode 100644 index 0000000000..7f2729ceff --- /dev/null +++ b/lib/tevent/testsuite.c @@ -0,0 +1,145 @@ +/* + Unix SMB/CIFS implementation. + + testing of the events subsystem + + Copyright (C) Stefan Metzmacher + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "lib/events/events.h" +#include "system/filesys.h" +#include "torture/torture.h" + +static int fde_count; + +static void fde_handler(struct event_context *ev_ctx, struct fd_event *f, + uint16_t flags, void *private) +{ + int *fd = (int *)private; + char c; +#ifdef SA_SIGINFO + kill(getpid(), SIGUSR1); +#endif + kill(getpid(), SIGALRM); + read(fd[0], &c, 1); + write(fd[1], &c, 1); + fde_count++; +} + +static void finished_handler(struct event_context *ev_ctx, struct timed_event *te, + struct timeval tval, void *private) +{ + int *finished = (int *)private; + (*finished) = 1; +} + +static void count_handler(struct event_context *ev_ctx, struct signal_event *te, + int signum, int count, void *info, void *private) +{ + int *countp = (int *)private; + (*countp) += count; +} + +static bool test_event_context(struct torture_context *test, + const void *test_data) +{ + struct event_context *ev_ctx; + int fd[2] = { -1, -1 }; + const char *backend = (const char *)test_data; + int alarm_count=0, info_count=0; + struct fd_event *fde; + struct signal_event *se1, *se2, *se3; + int finished=0; + struct timeval t; + char c = 0; + + ev_ctx = event_context_init_byname(test, backend); + if (ev_ctx == NULL) { + torture_comment(test, "event backend '%s' not supported\n", backend); + return true; + } + + torture_comment(test, "Testing event backend '%s'\n", backend); + + /* reset globals */ + fde_count = 0; + + /* create a pipe */ + pipe(fd); + + fde = event_add_fd(ev_ctx, ev_ctx, fd[0], EVENT_FD_READ|EVENT_FD_AUTOCLOSE, + fde_handler, fd); + + event_add_timed(ev_ctx, ev_ctx, timeval_current_ofs(2,0), + finished_handler, &finished); + + se1 = event_add_signal(ev_ctx, ev_ctx, SIGALRM, SA_RESTART, count_handler, &alarm_count); + se2 = event_add_signal(ev_ctx, ev_ctx, SIGALRM, SA_RESETHAND, count_handler, &alarm_count); +#ifdef SA_SIGINFO + se3 = event_add_signal(ev_ctx, ev_ctx, SIGUSR1, SA_SIGINFO, count_handler, &info_count); +#endif + + write(fd[1], &c, 1); + + t = timeval_current(); + while (!finished) { + errno = 0; + if (event_loop_once(ev_ctx) == -1) { + talloc_free(ev_ctx); + torture_fail(test, talloc_asprintf(test, "Failed event loop %s\n", strerror(errno))); + } + } + + talloc_free(fde); + close(fd[1]); + + while (alarm_count < fde_count+1) { + if (event_loop_once(ev_ctx) == -1) { + break; + } + } + + torture_comment(test, "Got %.2f pipe events/sec\n", fde_count/timeval_elapsed(&t)); + + talloc_free(se1); + + torture_assert_int_equal(test, alarm_count, 1+fde_count, "alarm count mismatch"); + +#ifdef SA_SIGINFO + talloc_free(se3); + torture_assert_int_equal(test, info_count, fde_count, "info count mismatch"); +#endif + + talloc_free(ev_ctx); + + return true; +} + +struct torture_suite *torture_local_event(TALLOC_CTX *mem_ctx) +{ + struct torture_suite *suite = torture_suite_create(mem_ctx, "EVENT"); + const char **list = event_backend_list(suite); + int i; + + for (i=0;list && list[i];i++) { + torture_suite_add_simple_tcase_const(suite, list[i], + test_event_context, + (const void *)list[i]); + } + + return suite; +} diff --git a/lib/tevent/tevent.c b/lib/tevent/tevent.c new file mode 100644 index 0000000000..cd470c93ae --- /dev/null +++ b/lib/tevent/tevent.c @@ -0,0 +1,310 @@ +/* + Unix SMB/CIFS implementation. + main select loop and event handling + Copyright (C) Andrew Tridgell 2003 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +/* + PLEASE READ THIS BEFORE MODIFYING! + + This module is a general abstraction for the main select loop and + event handling. Do not ever put any localised hacks in here, instead + register one of the possible event types and implement that event + somewhere else. + + There are 2 types of event handling that are handled in this module: + + 1) a file descriptor becoming readable or writeable. This is mostly + used for network sockets, but can be used for any type of file + descriptor. You may only register one handler for each file + descriptor/io combination or you will get unpredictable results + (this means that you can have a handler for read events, and a + separate handler for write events, but not two handlers that are + both handling read events) + + 2) a timed event. You can register an event that happens at a + specific time. You can register as many of these as you + like. They are single shot - add a new timed event in the event + handler to get another event. + + To setup a set of events you first need to create a event_context + structure using the function event_context_init(); This returns a + 'struct event_context' that you use in all subsequent calls. + + After that you can add/remove events that you are interested in + using event_add_*() and talloc_free() + + Finally, you call event_loop_wait_once() to block waiting for one of the + events to occor or event_loop_wait() which will loop + forever. + +*/ +#include "replace.h" +#include "tevent.h" +#include "tevent_internal.h" +#include "tevent_util.h" + +struct event_ops_list { + struct event_ops_list *next, *prev; + const char *name; + const struct event_ops *ops; +}; + +/* list of registered event backends */ +static struct event_ops_list *event_backends = NULL; +static char *event_default_backend = NULL; + +/* + register an events backend +*/ +bool event_register_backend(const char *name, const struct event_ops *ops) +{ + struct event_ops_list *e; + + for (e = event_backends; e != NULL; e = e->next) { + if (0 == strcmp(e->name, name)) { + /* already registered, skip it */ + return true; + } + } + + e = talloc(talloc_autofree_context(), struct event_ops_list); + if (e == NULL) return false; + + e->name = name; + e->ops = ops; + DLIST_ADD(event_backends, e); + + return true; +} + +/* + set the default event backend + */ +void event_set_default_backend(const char *backend) +{ + if (event_default_backend) free(event_default_backend); + event_default_backend = strdup(backend); +} + +/* + initialise backends if not already done +*/ +static void event_backend_init(void) +{ + events_select_init(); + events_standard_init(); +#if HAVE_EVENTS_EPOLL + events_epoll_init(); +#endif +#if HAVE_LINUX_AIO + events_aio_init(); +#endif +} + +/* + list available backends +*/ +const char **event_backend_list(TALLOC_CTX *mem_ctx) +{ + const char **list = NULL; + struct event_ops_list *e; + + event_backend_init(); + + for (e=event_backends;e;e=e->next) { + list = ev_str_list_add(list, e->name); + } + + talloc_steal(mem_ctx, list); + + return list; +} + +/* + create a event_context structure for a specific implemementation. + This must be the first events call, and all subsequent calls pass + this event_context as the first element. Event handlers also + receive this as their first argument. + + This function is for allowing third-party-applications to hook in gluecode + to their own event loop code, so that they can make async usage of our client libs + + NOTE: use event_context_init() inside of samba! +*/ +static struct event_context *event_context_init_ops(TALLOC_CTX *mem_ctx, + const struct event_ops *ops) +{ + struct event_context *ev; + int ret; + + ev = talloc_zero(mem_ctx, struct event_context); + if (!ev) return NULL; + + ev->ops = ops; + + ret = ev->ops->context_init(ev); + if (ret != 0) { + talloc_free(ev); + return NULL; + } + + return ev; +} + +/* + create a event_context structure. This must be the first events + call, and all subsequent calls pass this event_context as the first + element. Event handlers also receive this as their first argument. +*/ +struct event_context *event_context_init_byname(TALLOC_CTX *mem_ctx, const char *name) +{ + struct event_ops_list *e; + + event_backend_init(); + + if (name == NULL) { + name = event_default_backend; + } + if (name == NULL) { + name = "standard"; + } + + for (e=event_backends;e;e=e->next) { + if (strcmp(name, e->name) == 0) { + return event_context_init_ops(mem_ctx, e->ops); + } + } + return NULL; +} + + +/* + create a event_context structure. This must be the first events + call, and all subsequent calls pass this event_context as the first + element. Event handlers also receive this as their first argument. +*/ +struct event_context *event_context_init(TALLOC_CTX *mem_ctx) +{ + return event_context_init_byname(mem_ctx, NULL); +} + +/* + add a fd based event + return NULL on failure (memory allocation error) + + if flags contains EVENT_FD_AUTOCLOSE then the fd will be closed when + the returned fd_event context is freed +*/ +struct fd_event *event_add_fd(struct event_context *ev, TALLOC_CTX *mem_ctx, + int fd, uint16_t flags, event_fd_handler_t handler, + void *private_data) +{ + return ev->ops->add_fd(ev, mem_ctx, fd, flags, handler, private_data); +} + +/* + add a disk aio event +*/ +struct aio_event *event_add_aio(struct event_context *ev, + TALLOC_CTX *mem_ctx, + struct iocb *iocb, + event_aio_handler_t handler, + void *private_data) +{ + if (ev->ops->add_aio == NULL) return NULL; + return ev->ops->add_aio(ev, mem_ctx, iocb, handler, private_data); +} + +/* + return the fd event flags +*/ +uint16_t event_get_fd_flags(struct fd_event *fde) +{ + if (!fde) return 0; + return fde->event_ctx->ops->get_fd_flags(fde); +} + +/* + set the fd event flags +*/ +void event_set_fd_flags(struct fd_event *fde, uint16_t flags) +{ + if (!fde) return; + fde->event_ctx->ops->set_fd_flags(fde, flags); +} + +/* + add a timed event + return NULL on failure +*/ +struct timed_event *event_add_timed(struct event_context *ev, TALLOC_CTX *mem_ctx, + struct timeval next_event, + event_timed_handler_t handler, + void *private_data) +{ + return ev->ops->add_timed(ev, mem_ctx, next_event, handler, private_data); +} + +/* + add a signal event + + sa_flags are flags to sigaction(2) + + return NULL on failure +*/ +struct signal_event *event_add_signal(struct event_context *ev, TALLOC_CTX *mem_ctx, + int signum, + int sa_flags, + event_signal_handler_t handler, + void *private_data) +{ + return ev->ops->add_signal(ev, mem_ctx, signum, sa_flags, handler, private_data); +} + +/* + do a single event loop using the events defined in ev +*/ +int event_loop_once(struct event_context *ev) +{ + return ev->ops->loop_once(ev); +} + +/* + return on failure or (with 0) if all fd events are removed +*/ +int event_loop_wait(struct event_context *ev) +{ + return ev->ops->loop_wait(ev); +} + +/* + find an event context that is a parent of the given memory context, + or create a new event context as a child of the given context if + none is found + + This should be used in preference to event_context_init() in places + where you would prefer to use the existing event context if possible + (which is most situations) +*/ +struct event_context *event_context_find(TALLOC_CTX *mem_ctx) +{ + struct event_context *ev = talloc_find_parent_bytype(mem_ctx, struct event_context); + if (ev == NULL) { + ev = event_context_init(mem_ctx); + } + return ev; +} diff --git a/lib/tevent/tevent.h b/lib/tevent/tevent.h new file mode 100644 index 0000000000..1857f9bb10 --- /dev/null +++ b/lib/tevent/tevent.h @@ -0,0 +1,98 @@ +/* + Unix SMB/CIFS implementation. + + generalised event loop handling + + Copyright (C) Andrew Tridgell 2005 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef __TEVENT_H__ +#define __TEVENT_H__ + +#include <stdint.h> +#include <talloc.h> + +struct event_context; +struct event_ops; +struct fd_event; +struct timed_event; +struct aio_event; +struct signal_event; + +/* event handler types */ +typedef void (*event_fd_handler_t)(struct event_context *, struct fd_event *, + uint16_t , void *); +typedef void (*event_timed_handler_t)(struct event_context *, struct timed_event *, + struct timeval , void *); +typedef void (*event_signal_handler_t)(struct event_context *, struct signal_event *, + int , int, void *, void *); +typedef void (*event_aio_handler_t)(struct event_context *, struct aio_event *, + int, void *); + +#ifdef _SAMBA_BUILD_ +struct event_context *s4_event_context_init(TALLOC_CTX *mem_ctx); +#endif + +struct event_context *event_context_init(TALLOC_CTX *mem_ctx); +struct event_context *event_context_init_byname(TALLOC_CTX *mem_ctx, const char *name); +const char **event_backend_list(TALLOC_CTX *mem_ctx); +void event_set_default_backend(const char *backend); + +struct fd_event *event_add_fd(struct event_context *ev, TALLOC_CTX *mem_ctx, + int fd, uint16_t flags, event_fd_handler_t handler, + void *private_data); + +struct timed_event *event_add_timed(struct event_context *ev, TALLOC_CTX *mem_ctx, + struct timeval next_event, + event_timed_handler_t handler, + void *private_data); + +struct signal_event *event_add_signal(struct event_context *ev, TALLOC_CTX *mem_ctx, + int signum, int sa_flags, + event_signal_handler_t handler, + void *private_data); + +struct iocb; +struct aio_event *event_add_aio(struct event_context *ev, + TALLOC_CTX *mem_ctx, + struct iocb *iocb, + event_aio_handler_t handler, + void *private_data); + +int event_loop_once(struct event_context *ev); +int event_loop_wait(struct event_context *ev); + +uint16_t event_get_fd_flags(struct fd_event *fde); +void event_set_fd_flags(struct fd_event *fde, uint16_t flags); + +struct event_context *event_context_find(TALLOC_CTX *mem_ctx); + +/* bits for file descriptor event flags */ +#define EVENT_FD_READ 1 +#define EVENT_FD_WRITE 2 +#define EVENT_FD_AUTOCLOSE 4 + +#define EVENT_FD_WRITEABLE(fde) \ + event_set_fd_flags(fde, event_get_fd_flags(fde) | EVENT_FD_WRITE) +#define EVENT_FD_READABLE(fde) \ + event_set_fd_flags(fde, event_get_fd_flags(fde) | EVENT_FD_READ) + +#define EVENT_FD_NOT_WRITEABLE(fde) \ + event_set_fd_flags(fde, event_get_fd_flags(fde) & ~EVENT_FD_WRITE) +#define EVENT_FD_NOT_READABLE(fde) \ + event_set_fd_flags(fde, event_get_fd_flags(fde) & ~EVENT_FD_READ) + +#endif /* __TEVENT_H__ */ diff --git a/lib/tevent/tevent.mk b/lib/tevent/tevent.mk new file mode 100644 index 0000000000..2bc6221689 --- /dev/null +++ b/lib/tevent/tevent.mk @@ -0,0 +1,59 @@ + +EVENTS_SONAME = libevents.$(SHLIBEXT).0 +EVENTS_SOLIB = libevents.$(SHLIBEXT).$(PACKAGE_VERSION) + +libevents.a: $(EVENTS_OBJ) + ar -rv libevents.a $(EVENTS_OBJ) + +libevents.$(SHLIBEXT): $(EVENTS_SOLIB) + ln -fs $< $@ + +$(EVENTS_SONAME): $(EVENTS_SOLIB) + ln -fs $< $@ + +dirs:: + @mkdir -p lib + +installdirs:: + mkdir -p $(DESTDIR)$(includedir) + mkdir -p $(DESTDIR)$(libdir) + mkdir -p $(DESTDIR)$(libdir)/pkgconfig + +installheaders:: installdirs + cp $(srcdir)/events.h $(DESTDIR)$(includedir) + +installlibs:: installdirs + cp events.pc $(DESTDIR)$(libdir)/pkgconfig + cp libevents.a $(EVENTS_SOLIB) $(DESTDIR)$(libdir) + +install:: all installdirs installheaders installlibs $(PYTHON_INSTALL_TARGET) + +clean:: + rm -f $(EVENTS_SONAME) $(EVENTS_SOLIB) libevents.a libevents.$(SHLIBEXT) + rm -f events.pc + rm -f _libevents.$(SHLIBEXT) + + +#python stuff + +check-python:: build-python + $(LIB_PATH_VAR)=. PYTHONPATH=".:$(eventsdir)" $(PYTHON) $(eventsdir)/python/tests/simple.py + +install-swig:: + mkdir -p $(DESTDIR)`$(SWIG) -swiglib` + cp events.i $(DESTDIR)`$(SWIG) -swiglib` + +build-python:: _libevents.$(SHLIBEXT) + +events_wrap.o: $(eventsdir)/events_wrap.c + $(CC) $(PICFLAG) -c $(eventsdir)/events_wrap.c $(CFLAGS) `$(PYTHON_CONFIG) --cflags` + +_libevents.$(SHLIBEXT): libevents.$(SHLIBEXT) events_wrap.o + $(SHLD) $(SHLD_FLAGS) -o $@ events_wrap.o -L. -levents `$(PYTHON_CONFIG) --libs` + +install-python:: build-python + mkdir -p $(DESTDIR)`$(PYTHON) -c "import distutils.sysconfig; print distutils.sysconfig.get_python_lib(0, prefix='$(prefix)')"` \ + $(DESTDIR)`$(PYTHON) -c "import distutils.sysconfig; print distutils.sysconfig.get_python_lib(1, prefix='$(prefix)')"` + cp $(eventsdir)/events.py $(DESTDIR)`$(PYTHON) -c "import distutils.sysconfig; print distutils.sysconfig.get_python_lib(0, prefix='$(prefix)')"` + cp _libevents.$(SHLIBEXT) $(DESTDIR)`$(PYTHON) -c "import distutils.sysconfig; print distutils.sysconfig.get_python_lib(1, prefix='$(prefix)')"` + diff --git a/lib/tevent/tevent.pc.in b/lib/tevent/tevent.pc.in new file mode 100644 index 0000000000..afd9fcc279 --- /dev/null +++ b/lib/tevent/tevent.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: events +Description: An event system library +Version: @PACKAGE_VERSION@ +Libs: -L${libdir} -ltevent +Cflags: -I${includedir} +URL: http://samba.org/ diff --git a/lib/tevent/tevent_aio.c b/lib/tevent/tevent_aio.c new file mode 100644 index 0000000000..7c3473b9a7 --- /dev/null +++ b/lib/tevent/tevent_aio.c @@ -0,0 +1,567 @@ +/* + Unix SMB/CIFS implementation. + + main select loop and event handling - aio/epoll hybrid implementation + + Copyright (C) Andrew Tridgell 2006 + + based on events_standard.c + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ +/* + this is a very strange beast. The Linux AIO implementation doesn't + yet integrate properly with epoll, but there is a kernel patch that + allows the aio wait primitives to be used to wait for epoll events, + and this can be used to give us a unified event system incorporating + both aio events and epoll events + + this is _very_ experimental code +*/ + +#include "system/filesys.h" +#include "replace.h" +#include "tevent.h" +#include "tevent_internal.h" +#include "tevent_util.h" +#include <sys/epoll.h> +#include <libaio.h> + +#define MAX_AIO_QUEUE_DEPTH 100 +#ifndef IOCB_CMD_EPOLL_WAIT +#define IOCB_CMD_EPOLL_WAIT 9 +#endif + +struct aio_event_context { + /* a pointer back to the generic event_context */ + struct event_context *ev; + + /* list of filedescriptor events */ + struct fd_event *fd_events; + + /* number of registered fd event handlers */ + int num_fd_events; + + uint32_t destruction_count; + + io_context_t ioctx; + + struct epoll_event epevent[MAX_AIO_QUEUE_DEPTH]; + + struct iocb *epoll_iocb; + + int epoll_fd; + int is_epoll_set; + pid_t pid; +}; + +struct aio_event { + struct event_context *event_ctx; + struct iocb iocb; + void *private_data; + event_aio_handler_t handler; +}; + +/* + map from EVENT_FD_* to EPOLLIN/EPOLLOUT +*/ +static uint32_t epoll_map_flags(uint16_t flags) +{ + uint32_t ret = 0; + if (flags & EVENT_FD_READ) ret |= (EPOLLIN | EPOLLERR | EPOLLHUP); + if (flags & EVENT_FD_WRITE) ret |= (EPOLLOUT | EPOLLERR | EPOLLHUP); + return ret; +} + +/* + free the epoll fd +*/ +static int aio_ctx_destructor(struct aio_event_context *aio_ev) +{ + io_queue_release(aio_ev->ioctx); + close(aio_ev->epoll_fd); + aio_ev->epoll_fd = -1; + return 0; +} + +static void epoll_add_event(struct aio_event_context *aio_ev, struct fd_event *fde); + +/* + reopen the epoll handle when our pid changes + see http://junkcode.samba.org/ftp/unpacked/junkcode/epoll_fork.c for an + demonstration of why this is needed + */ +static void epoll_check_reopen(struct aio_event_context *aio_ev) +{ + struct fd_event *fde; + + if (aio_ev->pid == getpid()) { + return; + } + + close(aio_ev->epoll_fd); + aio_ev->epoll_fd = epoll_create(MAX_AIO_QUEUE_DEPTH); + if (aio_ev->epoll_fd == -1) { + ev_debug(aio_ev->ev, EV_DEBUG_FATAL, "Failed to recreate epoll handle after fork\n"); + return; + } + aio_ev->pid = getpid(); + for (fde=aio_ev->fd_events;fde;fde=fde->next) { + epoll_add_event(aio_ev, fde); + } +} + +#define EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT (1<<0) +#define EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR (1<<1) +#define EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR (1<<2) + +/* + add the epoll event to the given fd_event +*/ +static void epoll_add_event(struct aio_event_context *aio_ev, struct fd_event *fde) +{ + struct epoll_event event; + if (aio_ev->epoll_fd == -1) return; + + fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR; + + /* if we don't want events yet, don't add an aio_event */ + if (fde->flags == 0) return; + + memset(&event, 0, sizeof(event)); + event.events = epoll_map_flags(fde->flags); + event.data.ptr = fde; + epoll_ctl(aio_ev->epoll_fd, EPOLL_CTL_ADD, fde->fd, &event); + fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT; + + /* only if we want to read we want to tell the event handler about errors */ + if (fde->flags & EVENT_FD_READ) { + fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR; + } +} + +/* + delete the epoll event for given fd_event +*/ +static void epoll_del_event(struct aio_event_context *aio_ev, struct fd_event *fde) +{ + struct epoll_event event; + + DLIST_REMOVE(aio_ev->fd_events, fde); + + if (aio_ev->epoll_fd == -1) return; + + fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR; + + /* if there's no aio_event, we don't need to delete it */ + if (!(fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT)) return; + + ZERO_STRUCT(event); + event.events = epoll_map_flags(fde->flags); + event.data.ptr = fde; + epoll_ctl(aio_ev->epoll_fd, EPOLL_CTL_DEL, fde->fd, &event); + + fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT; +} + +/* + change the epoll event to the given fd_event +*/ +static void epoll_mod_event(struct aio_event_context *aio_ev, struct fd_event *fde) +{ + struct epoll_event event; + if (aio_ev->epoll_fd == -1) return; + + fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR; + + ZERO_STRUCT(event); + event.events = epoll_map_flags(fde->flags); + event.data.ptr = fde; + epoll_ctl(aio_ev->epoll_fd, EPOLL_CTL_MOD, fde->fd, &event); + + /* only if we want to read we want to tell the event handler about errors */ + if (fde->flags & EVENT_FD_READ) { + fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR; + } +} + +static void epoll_change_event(struct aio_event_context *aio_ev, struct fd_event *fde) +{ + bool got_error = (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR); + bool want_read = (fde->flags & EVENT_FD_READ); + bool want_write= (fde->flags & EVENT_FD_WRITE); + + if (aio_ev->epoll_fd == -1) return; + + fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR; + + /* there's already an event */ + if (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT) { + if (want_read || (want_write && !got_error)) { + epoll_mod_event(aio_ev, fde); + return; + } + epoll_del_event(aio_ev, fde); + return; + } + + /* there's no aio_event attached to the fde */ + if (want_read || (want_write && !got_error)) { + DLIST_ADD(aio_ev->fd_events, fde); + epoll_add_event(aio_ev, fde); + return; + } +} + +static int setup_epoll_wait(struct aio_event_context *aio_ev) +{ + if (aio_ev->is_epoll_set) { + return 0; + } + memset(aio_ev->epoll_iocb, 0, sizeof(*aio_ev->epoll_iocb)); + aio_ev->epoll_iocb->aio_fildes = aio_ev->epoll_fd; + aio_ev->epoll_iocb->aio_lio_opcode = IOCB_CMD_EPOLL_WAIT; + aio_ev->epoll_iocb->aio_reqprio = 0; + + aio_ev->epoll_iocb->u.c.nbytes = MAX_AIO_QUEUE_DEPTH; + aio_ev->epoll_iocb->u.c.offset = -1; + aio_ev->epoll_iocb->u.c.buf = aio_ev->epevent; + + if (io_submit(aio_ev->ioctx, 1, &aio_ev->epoll_iocb) != 1) { + return -1; + } + aio_ev->is_epoll_set = 1; + + return 0; +} + + +/* + event loop handling using aio/epoll hybrid +*/ +static int aio_event_loop(struct aio_event_context *aio_ev, struct timeval *tvalp) +{ + int ret, i; + uint32_t destruction_count = ++aio_ev->destruction_count; + struct timespec timeout; + struct io_event events[8]; + + if (aio_ev->epoll_fd == -1) return -1; + + if (aio_ev->ev->num_signal_handlers && + common_event_check_signal(aio_ev->ev)) { + return 0; + } + + if (tvalp) { + timeout.tv_sec = tvalp->tv_sec; + timeout.tv_nsec = tvalp->tv_usec; + timeout.tv_nsec *= 1000; + } + + if (setup_epoll_wait(aio_ev) < 0) + return -1; + + ret = io_getevents(aio_ev->ioctx, 1, 8, + events, tvalp?&timeout:NULL); + + if (ret == -EINTR) { + if (aio_ev->ev->num_signal_handlers) { + common_event_check_signal(aio_ev->ev); + } + return 0; + } + + if (ret == 0 && tvalp) { + /* we don't care about a possible delay here */ + common_event_loop_timer_delay(aio_ev->ev); + return 0; + } + + for (i=0;i<ret;i++) { + struct io_event *event = &events[i]; + struct iocb *finished = event->obj; + + switch (finished->aio_lio_opcode) { + case IO_CMD_PWRITE: + case IO_CMD_PREAD: { + struct aio_event *ae = talloc_get_type(finished->data, + struct aio_event); + if (ae) { + talloc_set_destructor(ae, NULL); + ae->handler(ae->event_ctx, ae, + event->res, ae->private_data); + talloc_free(ae); + } + break; + } + case IOCB_CMD_EPOLL_WAIT: { + struct epoll_event *ep = (struct epoll_event *)finished->u.c.buf; + struct fd_event *fde; + uint16_t flags = 0; + int j; + + aio_ev->is_epoll_set = 0; + + for (j=0; j<event->res; j++, ep++) { + fde = talloc_get_type(ep->data.ptr, + struct fd_event); + if (fde == NULL) { + return -1; + } + if (ep->events & (EPOLLHUP|EPOLLERR)) { + fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR; + if (!(fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR)) { + epoll_del_event(aio_ev, fde); + continue; + } + flags |= EVENT_FD_READ; + } + if (ep->events & EPOLLIN) flags |= EVENT_FD_READ; + if (ep->events & EPOLLOUT) flags |= EVENT_FD_WRITE; + if (flags) { + fde->handler(aio_ev->ev, fde, flags, fde->private_data); + } + } + break; + } + } + if (destruction_count != aio_ev->destruction_count) { + return 0; + } + } + + return 0; +} + +/* + create a aio_event_context structure. +*/ +static int aio_event_context_init(struct event_context *ev) +{ + struct aio_event_context *aio_ev; + + aio_ev = talloc_zero(ev, struct aio_event_context); + if (!aio_ev) return -1; + + aio_ev->ev = ev; + aio_ev->epoll_iocb = talloc(aio_ev, struct iocb); + + if (io_queue_init(MAX_AIO_QUEUE_DEPTH, &aio_ev->ioctx) != 0) { + talloc_free(aio_ev); + return -1; + } + + aio_ev->epoll_fd = epoll_create(MAX_AIO_QUEUE_DEPTH); + if (aio_ev->epoll_fd == -1) { + talloc_free(aio_ev); + return -1; + } + aio_ev->pid = getpid(); + + talloc_set_destructor(aio_ev, aio_ctx_destructor); + + ev->additional_data = aio_ev; + + if (setup_epoll_wait(aio_ev) < 0) { + talloc_free(aio_ev); + return -1; + } + + return 0; +} + +/* + destroy an fd_event +*/ +static int aio_event_fd_destructor(struct fd_event *fde) +{ + struct event_context *ev = fde->event_ctx; + struct aio_event_context *aio_ev = talloc_get_type(ev->additional_data, + struct aio_event_context); + + epoll_check_reopen(aio_ev); + + aio_ev->num_fd_events--; + aio_ev->destruction_count++; + + epoll_del_event(aio_ev, fde); + + if (fde->flags & EVENT_FD_AUTOCLOSE) { + close(fde->fd); + fde->fd = -1; + } + + return 0; +} + +/* + add a fd based event + return NULL on failure (memory allocation error) +*/ +static struct fd_event *aio_event_add_fd(struct event_context *ev, TALLOC_CTX *mem_ctx, + int fd, uint16_t flags, + event_fd_handler_t handler, + void *private_data) +{ + struct aio_event_context *aio_ev = talloc_get_type(ev->additional_data, + struct aio_event_context); + struct fd_event *fde; + + epoll_check_reopen(aio_ev); + + fde = talloc(mem_ctx?mem_ctx:ev, struct fd_event); + if (!fde) return NULL; + + fde->event_ctx = ev; + fde->fd = fd; + fde->flags = flags; + fde->handler = handler; + fde->private_data = private_data; + fde->additional_flags = 0; + fde->additional_data = NULL; + + aio_ev->num_fd_events++; + talloc_set_destructor(fde, aio_event_fd_destructor); + + DLIST_ADD(aio_ev->fd_events, fde); + epoll_add_event(aio_ev, fde); + + return fde; +} + + +/* + return the fd event flags +*/ +static uint16_t aio_event_get_fd_flags(struct fd_event *fde) +{ + return fde->flags; +} + +/* + set the fd event flags +*/ +static void aio_event_set_fd_flags(struct fd_event *fde, uint16_t flags) +{ + struct event_context *ev; + struct aio_event_context *aio_ev; + + if (fde->flags == flags) return; + + ev = fde->event_ctx; + aio_ev = talloc_get_type(ev->additional_data, struct aio_event_context); + + fde->flags = flags; + + epoll_check_reopen(aio_ev); + + epoll_change_event(aio_ev, fde); +} + +/* + do a single event loop using the events defined in ev +*/ +static int aio_event_loop_once(struct event_context *ev) +{ + struct aio_event_context *aio_ev = talloc_get_type(ev->additional_data, + struct aio_event_context); + struct timeval tval; + + tval = common_event_loop_timer_delay(ev); + if (ev_timeval_is_zero(&tval)) { + return 0; + } + + epoll_check_reopen(aio_ev); + + return aio_event_loop(aio_ev, &tval); +} + +/* + return on failure or (with 0) if all fd events are removed +*/ +static int aio_event_loop_wait(struct event_context *ev) +{ + struct aio_event_context *aio_ev = talloc_get_type(ev->additional_data, + struct aio_event_context); + while (aio_ev->num_fd_events) { + if (aio_event_loop_once(ev) != 0) { + break; + } + } + + return 0; +} + +/* + called when a disk IO event needs to be cancelled +*/ +static int aio_destructor(struct aio_event *ae) +{ + struct event_context *ev = ae->event_ctx; + struct aio_event_context *aio_ev = talloc_get_type(ev->additional_data, + struct aio_event_context); + struct io_event result; + io_cancel(aio_ev->ioctx, &ae->iocb, &result); + /* TODO: handle errors from io_cancel()! */ + return 0; +} + +/* submit an aio disk IO event */ +static struct aio_event *aio_event_add_aio(struct event_context *ev, + TALLOC_CTX *mem_ctx, + struct iocb *iocb, + event_aio_handler_t handler, + void *private_data) +{ + struct aio_event_context *aio_ev = talloc_get_type(ev->additional_data, + struct aio_event_context); + struct iocb *iocbp; + struct aio_event *ae = talloc(mem_ctx?mem_ctx:ev, struct aio_event); + if (ae == NULL) return NULL; + + ae->event_ctx = ev; + ae->iocb = *iocb; + ae->handler = handler; + ae->private_data = private_data; + iocbp = &ae->iocb; + + if (io_submit(aio_ev->ioctx, 1, &iocbp) != 1) { + talloc_free(ae); + return NULL; + } + ae->iocb.data = ae; + talloc_set_destructor(ae, aio_destructor); + + return ae; +} + +static const struct event_ops aio_event_ops = { + .context_init = aio_event_context_init, + .add_fd = aio_event_add_fd, + .add_aio = aio_event_add_aio, + .get_fd_flags = aio_event_get_fd_flags, + .set_fd_flags = aio_event_set_fd_flags, + .add_timed = common_event_add_timed, + .add_signal = common_event_add_signal, + .loop_once = aio_event_loop_once, + .loop_wait = aio_event_loop_wait, +}; + +bool events_aio_init(void) +{ + return event_register_backend("aio", &aio_event_ops); +} + diff --git a/lib/tevent/tevent_debug.c b/lib/tevent/tevent_debug.c new file mode 100644 index 0000000000..a23ff09755 --- /dev/null +++ b/lib/tevent/tevent_debug.c @@ -0,0 +1,83 @@ +/* + Unix SMB/CIFS implementation. + + Copyright (C) Andrew Tridgell 2005 + Copyright (C) Jelmer Vernooij 2005 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "replace.h" +#include "tevent.h" +#include "tevent_internal.h" + +/******************************************************************** + * Debug wrapper functions, modeled (with lot's of code copied as is) + * after the ev debug wrapper functions + ********************************************************************/ + +/* + this allows the user to choose their own debug function +*/ +int ev_set_debug(struct event_context *ev, + void (*debug)(void *context, enum ev_debug_level level, + const char *fmt, va_list ap), + void *context) +{ + ev->debug_ops.debug = debug; + ev->debug_ops.context = context; + return 0; +} + +/* + debug function for ev_set_debug_stderr +*/ +void ev_debug_stderr(void *context, enum ev_debug_level level, + const char *fmt, va_list ap) PRINTF_ATTRIBUTE(3,0); +void ev_debug_stderr(void *context, enum ev_debug_level level, + const char *fmt, va_list ap) +{ + if (level <= EV_DEBUG_WARNING) { + vfprintf(stderr, fmt, ap); + } +} + +/* + convenience function to setup debug messages on stderr + messages of level EV_DEBUG_WARNING and higher are printed +*/ +int ev_set_debug_stderr(struct event_context *ev) +{ + return ev_set_debug(ev, ev_debug_stderr, ev); +} + +/* + * log a message + * + * The default debug action is to ignore debugging messages. + * This is the most appropriate action for a library. + * Applications using the library must decide where to + * redirect debugging messages +*/ +void ev_debug(struct event_context *ev, enum ev_debug_level level, const char *fmt, ...) +{ + va_list ap; + if (ev->debug_ops.debug == NULL) { + return; + } + va_start(ap, fmt); + ev->debug_ops.debug(ev->debug_ops.context, level, fmt, ap); + va_end(ap); +} + diff --git a/lib/tevent/tevent_epoll.c b/lib/tevent/tevent_epoll.c new file mode 100644 index 0000000000..1d03b7dbf0 --- /dev/null +++ b/lib/tevent/tevent_epoll.c @@ -0,0 +1,482 @@ +/* + Unix SMB/CIFS implementation. + + main select loop and event handling - epoll implementation + + Copyright (C) Andrew Tridgell 2003-2005 + Copyright (C) Stefan Metzmacher 2005 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "replace.h" +#include "system/filesys.h" +#include "system/network.h" +#include "tevent.h" +#include "tevent_internal.h" +#include "tevent_util.h" +#include <sys/epoll.h> + +struct epoll_event_context { + /* a pointer back to the generic event_context */ + struct event_context *ev; + + /* list of filedescriptor events */ + struct fd_event *fd_events; + + /* number of registered fd event handlers */ + int num_fd_events; + + /* this is changed by the destructors for the fd event + type. It is used to detect event destruction by event + handlers, which means the code that is calling the event + handler needs to assume that the linked list is no longer + valid + */ + uint32_t destruction_count; + + /* when using epoll this is the handle from epoll_create */ + int epoll_fd; + + pid_t pid; +}; + +/* + called when a epoll call fails, and we should fallback + to using select +*/ +static void epoll_panic(struct epoll_event_context *epoll_ev, const char *reason) +{ + ev_debug(epoll_ev->ev, EV_DEBUG_FATAL, + "%s (%s) - calling abort()\n", reason, strerror(errno)); + abort(); +} + +/* + map from EVENT_FD_* to EPOLLIN/EPOLLOUT +*/ +static uint32_t epoll_map_flags(uint16_t flags) +{ + uint32_t ret = 0; + if (flags & EVENT_FD_READ) ret |= (EPOLLIN | EPOLLERR | EPOLLHUP); + if (flags & EVENT_FD_WRITE) ret |= (EPOLLOUT | EPOLLERR | EPOLLHUP); + return ret; +} + +/* + free the epoll fd +*/ +static int epoll_ctx_destructor(struct epoll_event_context *epoll_ev) +{ + close(epoll_ev->epoll_fd); + epoll_ev->epoll_fd = -1; + return 0; +} + +/* + init the epoll fd +*/ +static int epoll_init_ctx(struct epoll_event_context *epoll_ev) +{ + epoll_ev->epoll_fd = epoll_create(64); + epoll_ev->pid = getpid(); + talloc_set_destructor(epoll_ev, epoll_ctx_destructor); + if (epoll_ev->epoll_fd == -1) { + return -1; + } + return 0; +} + +static void epoll_add_event(struct epoll_event_context *epoll_ev, struct fd_event *fde); + +/* + reopen the epoll handle when our pid changes + see http://junkcode.samba.org/ftp/unpacked/junkcode/epoll_fork.c for an + demonstration of why this is needed + */ +static void epoll_check_reopen(struct epoll_event_context *epoll_ev) +{ + struct fd_event *fde; + + if (epoll_ev->pid == getpid()) { + return; + } + + close(epoll_ev->epoll_fd); + epoll_ev->epoll_fd = epoll_create(64); + if (epoll_ev->epoll_fd == -1) { + ev_debug(epoll_ev->ev, EV_DEBUG_FATAL, + "Failed to recreate epoll handle after fork\n"); + return; + } + epoll_ev->pid = getpid(); + for (fde=epoll_ev->fd_events;fde;fde=fde->next) { + epoll_add_event(epoll_ev, fde); + } +} + +#define EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT (1<<0) +#define EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR (1<<1) +#define EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR (1<<2) + +/* + add the epoll event to the given fd_event +*/ +static void epoll_add_event(struct epoll_event_context *epoll_ev, struct fd_event *fde) +{ + struct epoll_event event; + + if (epoll_ev->epoll_fd == -1) return; + + fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR; + + /* if we don't want events yet, don't add an epoll_event */ + if (fde->flags == 0) return; + + ZERO_STRUCT(event); + event.events = epoll_map_flags(fde->flags); + event.data.ptr = fde; + if (epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_ADD, fde->fd, &event) != 0) { + epoll_panic(epoll_ev, "EPOLL_CTL_ADD failed"); + } + fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT; + + /* only if we want to read we want to tell the event handler about errors */ + if (fde->flags & EVENT_FD_READ) { + fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR; + } +} + +/* + delete the epoll event for given fd_event +*/ +static void epoll_del_event(struct epoll_event_context *epoll_ev, struct fd_event *fde) +{ + struct epoll_event event; + + if (epoll_ev->epoll_fd == -1) return; + + fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR; + + /* if there's no epoll_event, we don't need to delete it */ + if (!(fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT)) return; + + ZERO_STRUCT(event); + event.events = epoll_map_flags(fde->flags); + event.data.ptr = fde; + if (epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_DEL, fde->fd, &event) != 0) { + ev_debug(epoll_ev->ev, EV_DEBUG_FATAL, + "epoll_del_event failed! probable early close bug (%s)\n", + strerror(errno)); + } + fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT; +} + +/* + change the epoll event to the given fd_event +*/ +static void epoll_mod_event(struct epoll_event_context *epoll_ev, struct fd_event *fde) +{ + struct epoll_event event; + if (epoll_ev->epoll_fd == -1) return; + + fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR; + + ZERO_STRUCT(event); + event.events = epoll_map_flags(fde->flags); + event.data.ptr = fde; + if (epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_MOD, fde->fd, &event) != 0) { + epoll_panic(epoll_ev, "EPOLL_CTL_MOD failed"); + } + + /* only if we want to read we want to tell the event handler about errors */ + if (fde->flags & EVENT_FD_READ) { + fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR; + } +} + +static void epoll_change_event(struct epoll_event_context *epoll_ev, struct fd_event *fde) +{ + bool got_error = (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR); + bool want_read = (fde->flags & EVENT_FD_READ); + bool want_write= (fde->flags & EVENT_FD_WRITE); + + if (epoll_ev->epoll_fd == -1) return; + + fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR; + + /* there's already an event */ + if (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT) { + if (want_read || (want_write && !got_error)) { + epoll_mod_event(epoll_ev, fde); + return; + } + /* + * if we want to match the select behavior, we need to remove the epoll_event + * when the caller isn't interested in events. + * + * this is because epoll reports EPOLLERR and EPOLLHUP, even without asking for them + */ + epoll_del_event(epoll_ev, fde); + return; + } + + /* there's no epoll_event attached to the fde */ + if (want_read || (want_write && !got_error)) { + epoll_add_event(epoll_ev, fde); + return; + } +} + +/* + event loop handling using epoll +*/ +static int epoll_event_loop(struct epoll_event_context *epoll_ev, struct timeval *tvalp) +{ + int ret, i; +#define MAXEVENTS 32 + struct epoll_event events[MAXEVENTS]; + uint32_t destruction_count = ++epoll_ev->destruction_count; + int timeout = -1; + + if (epoll_ev->epoll_fd == -1) return -1; + + if (tvalp) { + /* it's better to trigger timed events a bit later than to early */ + timeout = ((tvalp->tv_usec+999) / 1000) + (tvalp->tv_sec*1000); + } + + if (epoll_ev->ev->num_signal_handlers && + common_event_check_signal(epoll_ev->ev)) { + return 0; + } + + ret = epoll_wait(epoll_ev->epoll_fd, events, MAXEVENTS, timeout); + + if (ret == -1 && errno == EINTR && epoll_ev->ev->num_signal_handlers) { + if (common_event_check_signal(epoll_ev->ev)) { + return 0; + } + } + + if (ret == -1 && errno != EINTR) { + epoll_panic(epoll_ev, "epoll_wait() failed"); + return -1; + } + + if (ret == 0 && tvalp) { + /* we don't care about a possible delay here */ + common_event_loop_timer_delay(epoll_ev->ev); + return 0; + } + + for (i=0;i<ret;i++) { + struct fd_event *fde = talloc_get_type(events[i].data.ptr, + struct fd_event); + uint16_t flags = 0; + + if (fde == NULL) { + epoll_panic(epoll_ev, "epoll_wait() gave bad data"); + return -1; + } + if (events[i].events & (EPOLLHUP|EPOLLERR)) { + fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR; + /* + * if we only wait for EVENT_FD_WRITE, we should not tell the + * event handler about it, and remove the epoll_event, + * as we only report errors when waiting for read events, + * to match the select() behavior + */ + if (!(fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR)) { + epoll_del_event(epoll_ev, fde); + continue; + } + flags |= EVENT_FD_READ; + } + if (events[i].events & EPOLLIN) flags |= EVENT_FD_READ; + if (events[i].events & EPOLLOUT) flags |= EVENT_FD_WRITE; + if (flags) { + fde->handler(epoll_ev->ev, fde, flags, fde->private_data); + if (destruction_count != epoll_ev->destruction_count) { + break; + } + } + } + + return 0; +} + +/* + create a epoll_event_context structure. +*/ +static int epoll_event_context_init(struct event_context *ev) +{ + int ret; + struct epoll_event_context *epoll_ev; + + epoll_ev = talloc_zero(ev, struct epoll_event_context); + if (!epoll_ev) return -1; + epoll_ev->ev = ev; + epoll_ev->epoll_fd = -1; + + ret = epoll_init_ctx(epoll_ev); + if (ret != 0) { + talloc_free(epoll_ev); + return ret; + } + + ev->additional_data = epoll_ev; + return 0; +} + +/* + destroy an fd_event +*/ +static int epoll_event_fd_destructor(struct fd_event *fde) +{ + struct event_context *ev = fde->event_ctx; + struct epoll_event_context *epoll_ev = talloc_get_type(ev->additional_data, + struct epoll_event_context); + + epoll_check_reopen(epoll_ev); + + epoll_ev->num_fd_events--; + epoll_ev->destruction_count++; + + DLIST_REMOVE(epoll_ev->fd_events, fde); + + epoll_del_event(epoll_ev, fde); + + if (fde->flags & EVENT_FD_AUTOCLOSE) { + close(fde->fd); + fde->fd = -1; + } + + return 0; +} + +/* + add a fd based event + return NULL on failure (memory allocation error) +*/ +static struct fd_event *epoll_event_add_fd(struct event_context *ev, TALLOC_CTX *mem_ctx, + int fd, uint16_t flags, + event_fd_handler_t handler, + void *private_data) +{ + struct epoll_event_context *epoll_ev = talloc_get_type(ev->additional_data, + struct epoll_event_context); + struct fd_event *fde; + + epoll_check_reopen(epoll_ev); + + fde = talloc(mem_ctx?mem_ctx:ev, struct fd_event); + if (!fde) return NULL; + + fde->event_ctx = ev; + fde->fd = fd; + fde->flags = flags; + fde->handler = handler; + fde->private_data = private_data; + fde->additional_flags = 0; + fde->additional_data = NULL; + + epoll_ev->num_fd_events++; + talloc_set_destructor(fde, epoll_event_fd_destructor); + + DLIST_ADD(epoll_ev->fd_events, fde); + epoll_add_event(epoll_ev, fde); + + return fde; +} + + +/* + return the fd event flags +*/ +static uint16_t epoll_event_get_fd_flags(struct fd_event *fde) +{ + return fde->flags; +} + +/* + set the fd event flags +*/ +static void epoll_event_set_fd_flags(struct fd_event *fde, uint16_t flags) +{ + struct event_context *ev; + struct epoll_event_context *epoll_ev; + + if (fde->flags == flags) return; + + ev = fde->event_ctx; + epoll_ev = talloc_get_type(ev->additional_data, struct epoll_event_context); + + fde->flags = flags; + + epoll_check_reopen(epoll_ev); + + epoll_change_event(epoll_ev, fde); +} + +/* + do a single event loop using the events defined in ev +*/ +static int epoll_event_loop_once(struct event_context *ev) +{ + struct epoll_event_context *epoll_ev = talloc_get_type(ev->additional_data, + struct epoll_event_context); + struct timeval tval; + + tval = common_event_loop_timer_delay(ev); + if (ev_timeval_is_zero(&tval)) { + return 0; + } + + epoll_check_reopen(epoll_ev); + + return epoll_event_loop(epoll_ev, &tval); +} + +/* + return on failure or (with 0) if all fd events are removed +*/ +static int epoll_event_loop_wait(struct event_context *ev) +{ + struct epoll_event_context *epoll_ev = talloc_get_type(ev->additional_data, + struct epoll_event_context); + while (epoll_ev->num_fd_events) { + if (epoll_event_loop_once(ev) != 0) { + break; + } + } + + return 0; +} + +static const struct event_ops epoll_event_ops = { + .context_init = epoll_event_context_init, + .add_fd = epoll_event_add_fd, + .get_fd_flags = epoll_event_get_fd_flags, + .set_fd_flags = epoll_event_set_fd_flags, + .add_timed = common_event_add_timed, + .add_signal = common_event_add_signal, + .loop_once = epoll_event_loop_once, + .loop_wait = epoll_event_loop_wait, +}; + +bool events_epoll_init(void) +{ + return event_register_backend("epoll", &epoll_event_ops); +} diff --git a/lib/tevent/tevent_internal.h b/lib/tevent/tevent_internal.h new file mode 100644 index 0000000000..0d0755f298 --- /dev/null +++ b/lib/tevent/tevent_internal.h @@ -0,0 +1,158 @@ +/* + Unix SMB/CIFS implementation. + + generalised event loop handling + + Internal structs + + Copyright (C) Stefan Metzmacher 2005 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +struct event_ops { + /* conntext init */ + int (*context_init)(struct event_context *ev); + + /* fd_event functions */ + struct fd_event *(*add_fd)(struct event_context *ev, + TALLOC_CTX *mem_ctx, + int fd, uint16_t flags, + event_fd_handler_t handler, + void *private_data); + uint16_t (*get_fd_flags)(struct fd_event *fde); + void (*set_fd_flags)(struct fd_event *fde, uint16_t flags); + + /* timed_event functions */ + struct timed_event *(*add_timed)(struct event_context *ev, + TALLOC_CTX *mem_ctx, + struct timeval next_event, + event_timed_handler_t handler, + void *private_data); + /* disk aio event functions */ + struct aio_event *(*add_aio)(struct event_context *ev, + TALLOC_CTX *mem_ctx, + struct iocb *iocb, + event_aio_handler_t handler, + void *private_data); + /* signal functions */ + struct signal_event *(*add_signal)(struct event_context *ev, + TALLOC_CTX *mem_ctx, + int signum, int sa_flags, + event_signal_handler_t handler, + void *private_data); + + /* loop functions */ + int (*loop_once)(struct event_context *ev); + int (*loop_wait)(struct event_context *ev); +}; + +struct fd_event { + struct fd_event *prev, *next; + struct event_context *event_ctx; + int fd; + uint16_t flags; /* see EVENT_FD_* flags */ + event_fd_handler_t handler; + /* this is private for the specific handler */ + void *private_data; + /* this is private for the events_ops implementation */ + uint16_t additional_flags; + void *additional_data; +}; + +struct timed_event { + struct timed_event *prev, *next; + struct event_context *event_ctx; + struct timeval next_event; + event_timed_handler_t handler; + /* this is private for the specific handler */ + void *private_data; + /* this is private for the events_ops implementation */ + void *additional_data; +}; + +struct signal_event { + struct signal_event *prev, *next; + struct event_context *event_ctx; + event_signal_handler_t handler; + void *private_data; + int signum; + int sa_flags; +}; + +/* DEBUG */ +enum ev_debug_level {EV_DEBUG_FATAL, EV_DEBUG_ERROR, + EV_DEBUG_WARNING, EV_DEBUG_TRACE}; + +struct ev_debug_ops { + void (*debug)(void *context, enum ev_debug_level level, + const char *fmt, va_list ap) PRINTF_ATTRIBUTE(3,0); + void *context; +}; + +int ev_set_debug(struct event_context *ev, + void (*debug)(void *context, enum ev_debug_level level, + const char *fmt, va_list ap), + void *context); +int ev_set_debug_stderr(struct event_context *ev); +void ev_debug(struct event_context *ev, enum ev_debug_level level, const char *fmt, ...); + +/* aio event is private to the aio backend */ +struct aio_event; + +struct event_context { + /* the specific events implementation */ + const struct event_ops *ops; + + /* list of timed events - used by common code */ + struct timed_event *timed_events; + + /* this is private for the events_ops implementation */ + void *additional_data; + + /* number of signal event handlers */ + int num_signal_handlers; + + /* pipe hack used with signal handlers */ + struct fd_event *pipe_fde; + + /* debugging operations */ + struct ev_debug_ops debug_ops; +}; + + +bool event_register_backend(const char *name, const struct event_ops *ops); + +bool ev_timeval_is_zero(const struct timeval *tv); +struct timed_event *common_event_add_timed(struct event_context *, TALLOC_CTX *, + struct timeval, event_timed_handler_t, void *); +struct timeval common_event_loop_timer_delay(struct event_context *); + +struct signal_event *common_event_add_signal(struct event_context *ev, + TALLOC_CTX *mem_ctx, + int signum, + int sa_flags, + event_signal_handler_t handler, + void *private_data); +int common_event_check_signal(struct event_context *ev); + + +bool events_standard_init(void); +bool events_select_init(void); +#if HAVE_EVENTS_EPOLL +bool events_epoll_init(void); +#endif +#if HAVE_LINUX_AIO +bool events_aio_init(void); +#endif diff --git a/lib/tevent/tevent_liboop.c b/lib/tevent/tevent_liboop.c new file mode 100644 index 0000000000..339297a3cf --- /dev/null +++ b/lib/tevent/tevent_liboop.c @@ -0,0 +1,288 @@ +/* + Unix SMB/CIFS implementation. + main select loop and event handling + wrapper for http://liboop.org/ + + Copyright (C) Stefan Metzmacher 2005 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "events.h" +#include "events_internal.h" + +#include <oop.h> + +/* + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + NOTE: this code compiles fine, but is completly *UNTESTED* + and is only commited as example + + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +*/ + +static int oop_event_context_destructor(struct event_context *ev) +{ + oop_source_sys *oop_sys = ev->additional_data; + + oop_sys_delete(oop_sys); + + return 0; +} + +/* + create a oop_event_context structure. +*/ +static int oop_event_context_init(struct event_context *ev, void *private_data) +{ + oop_source_sys *oop_sys = private_data; + + if (!oop_sys) { + oop_sys = oop_sys_new(); + if (!oop_sys) { + return -1; + } + + talloc_set_destructor(ev, oop_event_context_destructor); + } + + ev->additional_data = oop_sys; + + return 0; +} + +static void *oop_event_fd_handler(oop_source *oop, int fd, oop_event oop_type, void *ptr) +{ + struct fd_event *fde = ptr; + + if (fd != fde->fd) return OOP_ERROR; + + switch(oop_type) { + case OOP_READ: + fde->handler(fde->event_ctx, fde, EVENT_FD_READ, fde->private_data); + return OOP_CONTINUE; + case OOP_WRITE: + fde->handler(fde->event_ctx, fde, EVENT_FD_WRITE, fde->private_data); + return OOP_CONTINUE; + case OOP_EXCEPTION: + return OOP_ERROR; + case OOP_NUM_EVENTS: + return OOP_ERROR; + } + + return OOP_ERROR; +} + +/* + destroy an fd_event +*/ +static int oop_event_fd_destructor(struct fd_event *fde) +{ + struct event_context *ev = fde->event_ctx; + oop_source_sys *oop_sys = ev->additional_data; + oop_source *oop = oop_sys_source(oop_sys); + + if (fde->flags & EVENT_FD_READ) + oop->cancel_fd(oop, fde->fd, OOP_READ); + if (fde->flags & EVENT_FD_WRITE) + oop->cancel_fd(oop, fde->fd, OOP_WRITE); + + if (fde->flags & EVENT_FD_AUTOCLOSE) { + close(fde->fd); + fde->fd = -1; + } + + return 0; +} + +/* + add a fd based event + return NULL on failure (memory allocation error) +*/ +static struct fd_event *oop_event_add_fd(struct event_context *ev, TALLOC_CTX *mem_ctx, + int fd, uint16_t flags, + event_fd_handler_t handler, + void *private_data) +{ + struct fd_event *fde; + oop_source_sys *oop_sys = ev->additional_data; + oop_source *oop = oop_sys_source(oop_sys); + + fde = talloc(mem_ctx?mem_ctx:ev, struct fd_event); + if (!fde) return NULL; + + fde->event_ctx = ev; + fde->fd = fd; + fde->flags = flags; + fde->handler = handler; + fde->private_data = private_data; + fde->additional_flags = 0; + fde->additional_data = NULL; + + if (fde->flags & EVENT_FD_READ) + oop->on_fd(oop, fde->fd, OOP_READ, oop_event_fd_handler, fde); + if (fde->flags & EVENT_FD_WRITE) + oop->on_fd(oop, fde->fd, OOP_WRITE, oop_event_fd_handler, fde); + + talloc_set_destructor(fde, oop_event_fd_destructor); + + return fde; +} + +/* + return the fd event flags +*/ +static uint16_t oop_event_get_fd_flags(struct fd_event *fde) +{ + return fde->flags; +} + +/* + set the fd event flags +*/ +static void oop_event_set_fd_flags(struct fd_event *fde, uint16_t flags) +{ + oop_source_sys *oop_sys; + oop_source *oop; + + oop_sys = fde->event_ctx->additional_data; + oop = oop_sys_source(oop_sys); + + if ((fde->flags & EVENT_FD_READ)&&(!(flags & EVENT_FD_READ))) + oop->cancel_fd(oop, fde->fd, OOP_READ); + + if ((!(fde->flags & EVENT_FD_READ))&&(flags & EVENT_FD_READ)) + oop->on_fd(oop, fde->fd, OOP_READ, oop_event_fd_handler, fde); + + if ((fde->flags & EVENT_FD_WRITE)&&(!(flags & EVENT_FD_WRITE))) + oop->cancel_fd(oop, fde->fd, OOP_WRITE); + + if ((!(fde->flags & EVENT_FD_WRITE))&&(flags & EVENT_FD_WRITE)) + oop->on_fd(oop, fde->fd, OOP_WRITE, oop_event_fd_handler, fde); + + fde->flags = flags; +} + +static int oop_event_timed_destructor(struct timed_event *te); + +static int oop_event_timed_deny_destructor(struct timed_event *te) +{ + return -1; +} + +static void *oop_event_timed_handler(oop_source *oop, struct timeval t, void *ptr) +{ + struct timed_event *te = ptr; + + /* deny the handler to free the event */ + talloc_set_destructor(te, oop_event_timed_deny_destructor); + te->handler(te->event_ctx, te, t, te->private_data); + + talloc_set_destructor(te, oop_event_timed_destructor); + talloc_free(te); + + return OOP_CONTINUE; +} + +/* + destroy a timed event +*/ +static int oop_event_timed_destructor(struct timed_event *te) +{ + struct event_context *ev = te->event_ctx; + oop_source_sys *oop_sys = ev->additional_data; + oop_source *oop = oop_sys_source(oop_sys); + + oop->cancel_time(oop, te->next_event, oop_event_timed_handler, te); + + return 0; +} + +/* + add a timed event + return NULL on failure (memory allocation error) +*/ +static struct timed_event *oop_event_add_timed(struct event_context *ev, TALLOC_CTX *mem_ctx, + struct timeval next_event, + event_timed_handler_t handler, + void *private_data) +{ + oop_source_sys *oop_sys = ev->additional_data; + oop_source *oop = oop_sys_source(oop_sys); + struct timed_event *te; + + te = talloc(mem_ctx?mem_ctx:ev, struct timed_event); + if (te == NULL) return NULL; + + te->event_ctx = ev; + te->next_event = next_event; + te->handler = handler; + te->private_data = private_data; + te->additional_data = NULL; + + oop->on_time(oop, te->next_event, oop_event_timed_handler, te); + + talloc_set_destructor(te, oop_event_timed_destructor); + + return te; +} + +/* + do a single event loop using the events defined in ev +*/ +static int oop_event_loop_once(struct event_context *ev) +{ + void *oop_ret; + oop_source_sys *oop_sys = ev->additional_data; + + oop_ret = oop_sys_run_once(oop_sys); + if (oop_ret == OOP_CONTINUE) { + return 0; + } + + return -1; +} + +/* + return on failure or (with 0) if all fd events are removed +*/ +static int oop_event_loop_wait(struct event_context *ev) +{ + void *oop_ret; + oop_source_sys *oop_sys = ev->additional_data; + + oop_ret = oop_sys_run(oop_sys); + if (oop_ret == OOP_CONTINUE) { + return 0; + } + + return -1; +} + +static const struct event_ops event_oop_ops = { + .context_init = oop_event_context_init, + .add_fd = oop_event_add_fd, + .get_fd_flags = oop_event_get_fd_flags, + .set_fd_flags = oop_event_set_fd_flags, + .add_timed = oop_event_add_timed, + .add_signal = common_event_add_signal, + .loop_once = oop_event_loop_once, + .loop_wait = oop_event_loop_wait, +}; + +const struct event_ops *event_liboop_get_ops(void) +{ + return &event_oop_ops; +} diff --git a/lib/tevent/tevent_s4.c b/lib/tevent/tevent_s4.c new file mode 100644 index 0000000000..4be92599a7 --- /dev/null +++ b/lib/tevent/tevent_s4.c @@ -0,0 +1,108 @@ +/* + Unix SMB/CIFS implementation. + Copyright (C) Andrew Tridgell 2003 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "tevent.h" +#include "tevent_internal.h" + +NTSTATUS s4_events_standard_init(void) +{ + if (!events_standard_init()) { + return NT_STATUS_INTERNAL_ERROR; + } + return NT_STATUS_OK; +} + +NTSTATUS s4_events_select_init(void) +{ + if (!events_select_init()) { + return NT_STATUS_INTERNAL_ERROR; + } + return NT_STATUS_OK; +} + +#if HAVE_EVENTS_EPOLL +NTSTATUS s4_events_epoll_init(void) +{ + if (!events_epoll_init()) { + return NT_STATUS_INTERNAL_ERROR; + } + return NT_STATUS_OK; +} +#endif + +#if HAVE_LINUX_AIO +NTSTATUS s4_events_aio_init(void) +{ + if (!events_aio_init()) { + return NT_STATUS_INTERNAL_ERROR; + } + return NT_STATUS_OK; +} +#endif + +/* + this is used to catch debug messages from events +*/ +static void ev_wrap_debug(void *context, enum ev_debug_level level, + const char *fmt, va_list ap) PRINTF_ATTRIBUTE(3,0); + +static void ev_wrap_debug(void *context, enum ev_debug_level level, + const char *fmt, va_list ap) +{ + int samba_level = -1; + char *s = NULL; + switch (level) { + case EV_DEBUG_FATAL: + samba_level = 0; + break; + case EV_DEBUG_ERROR: + samba_level = 1; + break; + case EV_DEBUG_WARNING: + samba_level = 2; + break; + case EV_DEBUG_TRACE: + samba_level = 5; + break; + + }; + vasprintf(&s, fmt, ap); + if (!s) return; + DEBUG(samba_level, ("events: %s\n", s)); + free(s); +} + +/* + create a event_context structure. This must be the first events + call, and all subsequent calls pass this event_context as the first + element. Event handlers also receive this as their first argument. + + This samba4 specific call sets the samba4 debug handler. +*/ +struct event_context *s4_event_context_init(TALLOC_CTX *mem_ctx) +{ + struct event_context *ev; + + ev = event_context_init_byname(mem_ctx, NULL); + if (ev) { + ev_set_debug(ev, ev_wrap_debug, NULL); + } + return ev; +} + diff --git a/lib/tevent/tevent_select.c b/lib/tevent/tevent_select.c new file mode 100644 index 0000000000..35c6f78599 --- /dev/null +++ b/lib/tevent/tevent_select.c @@ -0,0 +1,302 @@ +/* + Unix SMB/CIFS implementation. + main select loop and event handling + Copyright (C) Andrew Tridgell 2003-2005 + Copyright (C) Stefan Metzmacher 2005 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +/* + This is SAMBA's default event loop code + +*/ + +#include "replace.h" +#include "system/filesys.h" +#include "system/select.h" +#include "tevent.h" +#include "tevent_util.h" +#include "tevent_internal.h" + +struct select_event_context { + /* a pointer back to the generic event_context */ + struct event_context *ev; + + /* list of filedescriptor events */ + struct fd_event *fd_events; + + /* list of timed events */ + struct timed_event *timed_events; + + /* the maximum file descriptor number in fd_events */ + int maxfd; + + /* information for exiting from the event loop */ + int exit_code; + + /* this is incremented when the loop over events causes something which + could change the events yet to be processed */ + uint32_t destruction_count; +}; + +/* + create a select_event_context structure. +*/ +static int select_event_context_init(struct event_context *ev) +{ + struct select_event_context *select_ev; + + select_ev = talloc_zero(ev, struct select_event_context); + if (!select_ev) return -1; + select_ev->ev = ev; + + ev->additional_data = select_ev; + return 0; +} + +/* + recalculate the maxfd +*/ +static void calc_maxfd(struct select_event_context *select_ev) +{ + struct fd_event *fde; + + select_ev->maxfd = 0; + for (fde = select_ev->fd_events; fde; fde = fde->next) { + if (fde->fd > select_ev->maxfd) { + select_ev->maxfd = fde->fd; + } + } +} + + +/* to mark the ev->maxfd invalid + * this means we need to recalculate it + */ +#define EVENT_INVALID_MAXFD (-1) + +/* + destroy an fd_event +*/ +static int select_event_fd_destructor(struct fd_event *fde) +{ + struct event_context *ev = fde->event_ctx; + struct select_event_context *select_ev = talloc_get_type(ev->additional_data, + struct select_event_context); + + if (select_ev->maxfd == fde->fd) { + select_ev->maxfd = EVENT_INVALID_MAXFD; + } + + DLIST_REMOVE(select_ev->fd_events, fde); + select_ev->destruction_count++; + + if (fde->flags & EVENT_FD_AUTOCLOSE) { + close(fde->fd); + fde->fd = -1; + } + + return 0; +} + +/* + add a fd based event + return NULL on failure (memory allocation error) +*/ +static struct fd_event *select_event_add_fd(struct event_context *ev, TALLOC_CTX *mem_ctx, + int fd, uint16_t flags, + event_fd_handler_t handler, + void *private_data) +{ + struct select_event_context *select_ev = talloc_get_type(ev->additional_data, + struct select_event_context); + struct fd_event *fde; + + fde = talloc(mem_ctx?mem_ctx:ev, struct fd_event); + if (!fde) return NULL; + + fde->event_ctx = ev; + fde->fd = fd; + fde->flags = flags; + fde->handler = handler; + fde->private_data = private_data; + fde->additional_flags = 0; + fde->additional_data = NULL; + + DLIST_ADD(select_ev->fd_events, fde); + if (fde->fd > select_ev->maxfd) { + select_ev->maxfd = fde->fd; + } + talloc_set_destructor(fde, select_event_fd_destructor); + + return fde; +} + + +/* + return the fd event flags +*/ +static uint16_t select_event_get_fd_flags(struct fd_event *fde) +{ + return fde->flags; +} + +/* + set the fd event flags +*/ +static void select_event_set_fd_flags(struct fd_event *fde, uint16_t flags) +{ + struct event_context *ev; + struct select_event_context *select_ev; + + if (fde->flags == flags) return; + + ev = fde->event_ctx; + select_ev = talloc_get_type(ev->additional_data, struct select_event_context); + + fde->flags = flags; +} + +/* + event loop handling using select() +*/ +static int select_event_loop_select(struct select_event_context *select_ev, struct timeval *tvalp) +{ + fd_set r_fds, w_fds; + struct fd_event *fde; + int selrtn; + uint32_t destruction_count = ++select_ev->destruction_count; + + /* we maybe need to recalculate the maxfd */ + if (select_ev->maxfd == EVENT_INVALID_MAXFD) { + calc_maxfd(select_ev); + } + + FD_ZERO(&r_fds); + FD_ZERO(&w_fds); + + /* setup any fd events */ + for (fde = select_ev->fd_events; fde; fde = fde->next) { + if (fde->flags & EVENT_FD_READ) { + FD_SET(fde->fd, &r_fds); + } + if (fde->flags & EVENT_FD_WRITE) { + FD_SET(fde->fd, &w_fds); + } + } + + if (select_ev->ev->num_signal_handlers && + common_event_check_signal(select_ev->ev)) { + return 0; + } + + selrtn = select(select_ev->maxfd+1, &r_fds, &w_fds, NULL, tvalp); + + if (selrtn == -1 && errno == EINTR && + select_ev->ev->num_signal_handlers) { + common_event_check_signal(select_ev->ev); + return 0; + } + + if (selrtn == -1 && errno == EBADF) { + /* the socket is dead! this should never + happen as the socket should have first been + made readable and that should have removed + the event, so this must be a bug. This is a + fatal error. */ + ev_debug(select_ev->ev, EV_DEBUG_FATAL, + "ERROR: EBADF on select_event_loop_once\n"); + select_ev->exit_code = EBADF; + return -1; + } + + if (selrtn == 0 && tvalp) { + /* we don't care about a possible delay here */ + common_event_loop_timer_delay(select_ev->ev); + return 0; + } + + if (selrtn > 0) { + /* at least one file descriptor is ready - check + which ones and call the handler, being careful to allow + the handler to remove itself when called */ + for (fde = select_ev->fd_events; fde; fde = fde->next) { + uint16_t flags = 0; + + if (FD_ISSET(fde->fd, &r_fds)) flags |= EVENT_FD_READ; + if (FD_ISSET(fde->fd, &w_fds)) flags |= EVENT_FD_WRITE; + if (flags) { + fde->handler(select_ev->ev, fde, flags, fde->private_data); + if (destruction_count != select_ev->destruction_count) { + break; + } + } + } + } + + return 0; +} + +/* + do a single event loop using the events defined in ev +*/ +static int select_event_loop_once(struct event_context *ev) +{ + struct select_event_context *select_ev = talloc_get_type(ev->additional_data, + struct select_event_context); + struct timeval tval; + + tval = common_event_loop_timer_delay(ev); + if (ev_timeval_is_zero(&tval)) { + return 0; + } + + return select_event_loop_select(select_ev, &tval); +} + +/* + return on failure or (with 0) if all fd events are removed +*/ +static int select_event_loop_wait(struct event_context *ev) +{ + struct select_event_context *select_ev = talloc_get_type(ev->additional_data, + struct select_event_context); + select_ev->exit_code = 0; + + while (select_ev->fd_events && select_ev->exit_code == 0) { + if (select_event_loop_once(ev) != 0) { + break; + } + } + + return select_ev->exit_code; +} + +static const struct event_ops select_event_ops = { + .context_init = select_event_context_init, + .add_fd = select_event_add_fd, + .get_fd_flags = select_event_get_fd_flags, + .set_fd_flags = select_event_set_fd_flags, + .add_timed = common_event_add_timed, + .add_signal = common_event_add_signal, + .loop_once = select_event_loop_once, + .loop_wait = select_event_loop_wait, +}; + +bool events_select_init(void) +{ + return event_register_backend("select", &select_event_ops); +} + diff --git a/lib/tevent/tevent_signal.c b/lib/tevent/tevent_signal.c new file mode 100644 index 0000000000..36907af6be --- /dev/null +++ b/lib/tevent/tevent_signal.c @@ -0,0 +1,291 @@ +/* + Unix SMB/CIFS implementation. + + common events code for signal events + + Copyright (C) Andrew Tridgell 2007 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include <signal.h> +#include "replace.h" +#include "system/filesys.h" +#include "system/select.h" +#include "tevent.h" +#include "tevent_internal.h" +#include "tevent_util.h" + +#define NUM_SIGNALS 64 + +/* maximum number of SA_SIGINFO signals to hold in the queue */ +#define SA_INFO_QUEUE_COUNT 10 + +struct sigcounter { + uint32_t count; + uint32_t seen; +}; + +#define SIG_INCREMENT(s) (s).count++ +#define SIG_SEEN(s, n) (s).seen += (n) +#define SIG_PENDING(s) ((s).seen != (s).count) + + +/* + the poor design of signals means that this table must be static global +*/ +static struct sig_state { + struct signal_event *sig_handlers[NUM_SIGNALS+1]; + struct sigaction *oldact[NUM_SIGNALS+1]; + struct sigcounter signal_count[NUM_SIGNALS+1]; + struct sigcounter got_signal; + int pipe_hack[2]; +#ifdef SA_SIGINFO + /* with SA_SIGINFO we get quite a lot of info per signal */ + siginfo_t *sig_info[NUM_SIGNALS+1]; + struct sigcounter sig_blocked[NUM_SIGNALS+1]; +#endif +} *sig_state; + +/* + return number of sigcounter events not processed yet +*/ +static uint32_t sig_count(struct sigcounter s) +{ + if (s.count >= s.seen) { + return s.count - s.seen; + } + return 1 + (0xFFFFFFFF & ~(s.seen - s.count)); +} + +/* + signal handler - redirects to registered signals +*/ +static void signal_handler(int signum) +{ + char c = 0; + SIG_INCREMENT(sig_state->signal_count[signum]); + SIG_INCREMENT(sig_state->got_signal); + /* doesn't matter if this pipe overflows */ + write(sig_state->pipe_hack[1], &c, 1); +} + +#ifdef SA_SIGINFO +/* + signal handler with SA_SIGINFO - redirects to registered signals +*/ +static void signal_handler_info(int signum, siginfo_t *info, void *uctx) +{ + uint32_t count = sig_count(sig_state->signal_count[signum]); + sig_state->sig_info[signum][count] = *info; + + signal_handler(signum); + + /* handle SA_SIGINFO */ + if (count+1 == SA_INFO_QUEUE_COUNT) { + /* we've filled the info array - block this signal until + these ones are delivered */ + sigset_t set; + sigemptyset(&set); + sigaddset(&set, signum); + sigprocmask(SIG_BLOCK, &set, NULL); + SIG_INCREMENT(sig_state->sig_blocked[signum]); + } +} +#endif + +/* + destroy a signal event +*/ +static int signal_event_destructor(struct signal_event *se) +{ + se->event_ctx->num_signal_handlers--; + DLIST_REMOVE(sig_state->sig_handlers[se->signum], se); + if (sig_state->sig_handlers[se->signum] == NULL) { + /* restore old handler, if any */ + sigaction(se->signum, sig_state->oldact[se->signum], NULL); + sig_state->oldact[se->signum] = NULL; +#ifdef SA_SIGINFO + if (se->sa_flags & SA_SIGINFO) { + talloc_free(sig_state->sig_info[se->signum]); + sig_state->sig_info[se->signum] = NULL; + } +#endif + } + return 0; +} + +/* + this is part of the pipe hack needed to avoid the signal race condition +*/ +static void signal_pipe_handler(struct event_context *ev, struct fd_event *fde, + uint16_t flags, void *private) +{ + char c[16]; + /* its non-blocking, doesn't matter if we read too much */ + read(sig_state->pipe_hack[0], c, sizeof(c)); +} + +/* + add a signal event + return NULL on failure (memory allocation error) +*/ +struct signal_event *common_event_add_signal(struct event_context *ev, + TALLOC_CTX *mem_ctx, + int signum, + int sa_flags, + event_signal_handler_t handler, + void *private_data) +{ + struct signal_event *se; + + if (signum >= NUM_SIGNALS) { + return NULL; + } + + /* the sig_state needs to be on a global context as it can last across + multiple event contexts */ + if (sig_state == NULL) { + sig_state = talloc_zero(talloc_autofree_context(), struct sig_state); + if (sig_state == NULL) { + return NULL; + } + } + + se = talloc(mem_ctx?mem_ctx:ev, struct signal_event); + if (se == NULL) return NULL; + + se->event_ctx = ev; + se->handler = handler; + se->private_data = private_data; + se->signum = signum; + se->sa_flags = sa_flags; + + /* Ensure, no matter the destruction order, that we always have a handle on the global sig_state */ + if (!talloc_reference(se, sig_state)) { + return NULL; + } + + /* only install a signal handler if not already installed */ + if (sig_state->sig_handlers[signum] == NULL) { + struct sigaction act; + ZERO_STRUCT(act); + act.sa_handler = signal_handler; + act.sa_flags = sa_flags; +#ifdef SA_SIGINFO + if (sa_flags & SA_SIGINFO) { + act.sa_handler = NULL; + act.sa_sigaction = signal_handler_info; + if (sig_state->sig_info[signum] == NULL) { + sig_state->sig_info[signum] = talloc_array(sig_state, siginfo_t, SA_INFO_QUEUE_COUNT); + if (sig_state->sig_info[signum] == NULL) { + talloc_free(se); + return NULL; + } + } + } +#endif + sig_state->oldact[signum] = talloc(sig_state, struct sigaction); + if (sig_state->oldact[signum] == NULL) { + talloc_free(se); + return NULL; + } + if (sigaction(signum, &act, sig_state->oldact[signum]) == -1) { + talloc_free(se); + return NULL; + } + } + + DLIST_ADD(sig_state->sig_handlers[signum], se); + + talloc_set_destructor(se, signal_event_destructor); + + /* we need to setup the pipe hack handler if not already + setup */ + if (ev->pipe_fde == NULL) { + if (sig_state->pipe_hack[0] == 0 && + sig_state->pipe_hack[1] == 0) { + pipe(sig_state->pipe_hack); + ev_set_blocking(sig_state->pipe_hack[0], false); + ev_set_blocking(sig_state->pipe_hack[1], false); + } + ev->pipe_fde = event_add_fd(ev, ev, sig_state->pipe_hack[0], + EVENT_FD_READ, signal_pipe_handler, NULL); + } + ev->num_signal_handlers++; + + return se; +} + + +/* + check if a signal is pending + return != 0 if a signal was pending +*/ +int common_event_check_signal(struct event_context *ev) +{ + int i; + + if (!sig_state || !SIG_PENDING(sig_state->got_signal)) { + return 0; + } + + for (i=0;i<NUM_SIGNALS+1;i++) { + struct signal_event *se, *next; + struct sigcounter counter = sig_state->signal_count[i]; + uint32_t count = sig_count(counter); + + if (count == 0) { + continue; + } + for (se=sig_state->sig_handlers[i];se;se=next) { + next = se->next; +#ifdef SA_SIGINFO + if (se->sa_flags & SA_SIGINFO) { + int j; + for (j=0;j<count;j++) { + /* note the use of the sig_info array as a + ring buffer */ + int ofs = ((count-1) + j) % SA_INFO_QUEUE_COUNT; + se->handler(ev, se, i, 1, + (void*)&sig_state->sig_info[i][ofs], + se->private_data); + } + if (SIG_PENDING(sig_state->sig_blocked[i])) { + /* we'd filled the queue, unblock the + signal now */ + sigset_t set; + sigemptyset(&set); + sigaddset(&set, i); + SIG_SEEN(sig_state->sig_blocked[i], + sig_count(sig_state->sig_blocked[i])); + sigprocmask(SIG_UNBLOCK, &set, NULL); + } + if (se->sa_flags & SA_RESETHAND) { + talloc_free(se); + } + continue; + } +#endif + se->handler(ev, se, i, count, NULL, se->private_data); + if (se->sa_flags & SA_RESETHAND) { + talloc_free(se); + } + } + SIG_SEEN(sig_state->signal_count[i], count); + SIG_SEEN(sig_state->got_signal, count); + } + + return 1; +} diff --git a/lib/tevent/tevent_standard.c b/lib/tevent/tevent_standard.c new file mode 100644 index 0000000000..c63d092173 --- /dev/null +++ b/lib/tevent/tevent_standard.c @@ -0,0 +1,607 @@ +/* + Unix SMB/CIFS implementation. + main select loop and event handling + Copyright (C) Andrew Tridgell 2003-2005 + Copyright (C) Stefan Metzmacher 2005 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +/* + This is SAMBA's default event loop code + + - we try to use epoll if configure detected support for it + otherwise we use select() + - if epoll is broken on the system or the kernel doesn't support it + at runtime we fallback to select() +*/ + +#include "replace.h" +#include "system/filesys.h" +#include "system/network.h" +#include "system/select.h" /* needed for HAVE_EVENTS_EPOLL */ +#include "tevent.h" +#include "tevent_util.h" +#include "tevent_internal.h" + +struct std_event_context { + /* a pointer back to the generic event_context */ + struct event_context *ev; + + /* list of filedescriptor events */ + struct fd_event *fd_events; + + /* the maximum file descriptor number in fd_events */ + int maxfd; + + /* information for exiting from the event loop */ + int exit_code; + + /* this is changed by the destructors for the fd event + type. It is used to detect event destruction by event + handlers, which means the code that is calling the event + handler needs to assume that the linked list is no longer + valid + */ + uint32_t destruction_count; + + /* when using epoll this is the handle from epoll_create */ + int epoll_fd; + + /* our pid at the time the epoll_fd was created */ + pid_t pid; +}; + +/* use epoll if it is available */ +#if HAVE_EVENTS_EPOLL +/* + called when a epoll call fails, and we should fallback + to using select +*/ +static void epoll_fallback_to_select(struct std_event_context *std_ev, const char *reason) +{ + ev_debug(std_ev->ev, EV_DEBUG_FATAL, + "%s (%s) - falling back to select()\n", + reason, strerror(errno)); + close(std_ev->epoll_fd); + std_ev->epoll_fd = -1; + talloc_set_destructor(std_ev, NULL); +} + +/* + map from EVENT_FD_* to EPOLLIN/EPOLLOUT +*/ +static uint32_t epoll_map_flags(uint16_t flags) +{ + uint32_t ret = 0; + if (flags & EVENT_FD_READ) ret |= (EPOLLIN | EPOLLERR | EPOLLHUP); + if (flags & EVENT_FD_WRITE) ret |= (EPOLLOUT | EPOLLERR | EPOLLHUP); + return ret; +} + +/* + free the epoll fd +*/ +static int epoll_ctx_destructor(struct std_event_context *std_ev) +{ + if (std_ev->epoll_fd != -1) { + close(std_ev->epoll_fd); + } + std_ev->epoll_fd = -1; + return 0; +} + +/* + init the epoll fd +*/ +static void epoll_init_ctx(struct std_event_context *std_ev) +{ + std_ev->epoll_fd = epoll_create(64); + std_ev->pid = getpid(); + talloc_set_destructor(std_ev, epoll_ctx_destructor); +} + +static void epoll_add_event(struct std_event_context *std_ev, struct fd_event *fde); + +/* + reopen the epoll handle when our pid changes + see http://junkcode.samba.org/ftp/unpacked/junkcode/epoll_fork.c for an + demonstration of why this is needed + */ +static void epoll_check_reopen(struct std_event_context *std_ev) +{ + struct fd_event *fde; + + if (std_ev->pid == getpid()) { + return; + } + + close(std_ev->epoll_fd); + std_ev->epoll_fd = epoll_create(64); + if (std_ev->epoll_fd == -1) { + ev_debug(std_ev->ev, EV_DEBUG_FATAL, + "Failed to recreate epoll handle after fork\n"); + return; + } + std_ev->pid = getpid(); + for (fde=std_ev->fd_events;fde;fde=fde->next) { + epoll_add_event(std_ev, fde); + } +} + +#define EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT (1<<0) +#define EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR (1<<1) +#define EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR (1<<2) + +/* + add the epoll event to the given fd_event +*/ +static void epoll_add_event(struct std_event_context *std_ev, struct fd_event *fde) +{ + struct epoll_event event; + if (std_ev->epoll_fd == -1) return; + + fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR; + + /* if we don't want events yet, don't add an epoll_event */ + if (fde->flags == 0) return; + + ZERO_STRUCT(event); + event.events = epoll_map_flags(fde->flags); + event.data.ptr = fde; + if (epoll_ctl(std_ev->epoll_fd, EPOLL_CTL_ADD, fde->fd, &event) != 0) { + epoll_fallback_to_select(std_ev, "EPOLL_CTL_ADD failed"); + } + fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT; + + /* only if we want to read we want to tell the event handler about errors */ + if (fde->flags & EVENT_FD_READ) { + fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR; + } +} + +/* + delete the epoll event for given fd_event +*/ +static void epoll_del_event(struct std_event_context *std_ev, struct fd_event *fde) +{ + struct epoll_event event; + if (std_ev->epoll_fd == -1) return; + + fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR; + + /* if there's no epoll_event, we don't need to delete it */ + if (!(fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT)) return; + + ZERO_STRUCT(event); + event.events = epoll_map_flags(fde->flags); + event.data.ptr = fde; + epoll_ctl(std_ev->epoll_fd, EPOLL_CTL_DEL, fde->fd, &event); + fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT; +} + +/* + change the epoll event to the given fd_event +*/ +static void epoll_mod_event(struct std_event_context *std_ev, struct fd_event *fde) +{ + struct epoll_event event; + if (std_ev->epoll_fd == -1) return; + + fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR; + + ZERO_STRUCT(event); + event.events = epoll_map_flags(fde->flags); + event.data.ptr = fde; + if (epoll_ctl(std_ev->epoll_fd, EPOLL_CTL_MOD, fde->fd, &event) != 0) { + epoll_fallback_to_select(std_ev, "EPOLL_CTL_MOD failed"); + } + + /* only if we want to read we want to tell the event handler about errors */ + if (fde->flags & EVENT_FD_READ) { + fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR; + } +} + +static void epoll_change_event(struct std_event_context *std_ev, struct fd_event *fde) +{ + bool got_error = (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR); + bool want_read = (fde->flags & EVENT_FD_READ); + bool want_write= (fde->flags & EVENT_FD_WRITE); + + if (std_ev->epoll_fd == -1) return; + + fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR; + + /* there's already an event */ + if (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT) { + if (want_read || (want_write && !got_error)) { + epoll_mod_event(std_ev, fde); + return; + } + /* + * if we want to match the select behavior, we need to remove the epoll_event + * when the caller isn't interested in events. + * + * this is because epoll reports EPOLLERR and EPOLLHUP, even without asking for them + */ + epoll_del_event(std_ev, fde); + return; + } + + /* there's no epoll_event attached to the fde */ + if (want_read || (want_write && !got_error)) { + epoll_add_event(std_ev, fde); + return; + } +} + +/* + event loop handling using epoll +*/ +static int epoll_event_loop(struct std_event_context *std_ev, struct timeval *tvalp) +{ + int ret, i; +#define MAXEVENTS 8 + struct epoll_event events[MAXEVENTS]; + uint32_t destruction_count = ++std_ev->destruction_count; + int timeout = -1; + + if (std_ev->epoll_fd == -1) return -1; + + if (tvalp) { + /* it's better to trigger timed events a bit later than to early */ + timeout = ((tvalp->tv_usec+999) / 1000) + (tvalp->tv_sec*1000); + } + + if (std_ev->ev->num_signal_handlers && + common_event_check_signal(std_ev->ev)) { + return 0; + } + + ret = epoll_wait(std_ev->epoll_fd, events, MAXEVENTS, timeout); + + if (ret == -1 && errno == EINTR && std_ev->ev->num_signal_handlers) { + if (common_event_check_signal(std_ev->ev)) { + return 0; + } + } + + if (ret == -1 && errno != EINTR) { + epoll_fallback_to_select(std_ev, "epoll_wait() failed"); + return -1; + } + + if (ret == 0 && tvalp) { + /* we don't care about a possible delay here */ + common_event_loop_timer_delay(std_ev->ev); + return 0; + } + + for (i=0;i<ret;i++) { + struct fd_event *fde = talloc_get_type(events[i].data.ptr, + struct fd_event); + uint16_t flags = 0; + + if (fde == NULL) { + epoll_fallback_to_select(std_ev, "epoll_wait() gave bad data"); + return -1; + } + if (events[i].events & (EPOLLHUP|EPOLLERR)) { + fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR; + /* + * if we only wait for EVENT_FD_WRITE, we should not tell the + * event handler about it, and remove the epoll_event, + * as we only report errors when waiting for read events, + * to match the select() behavior + */ + if (!(fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR)) { + epoll_del_event(std_ev, fde); + continue; + } + flags |= EVENT_FD_READ; + } + if (events[i].events & EPOLLIN) flags |= EVENT_FD_READ; + if (events[i].events & EPOLLOUT) flags |= EVENT_FD_WRITE; + if (flags) { + fde->handler(std_ev->ev, fde, flags, fde->private_data); + if (destruction_count != std_ev->destruction_count) { + break; + } + } + } + + return 0; +} +#else +#define epoll_init_ctx(std_ev) +#define epoll_add_event(std_ev,fde) +#define epoll_del_event(std_ev,fde) +#define epoll_change_event(std_ev,fde) +#define epoll_event_loop(std_ev,tvalp) (-1) +#define epoll_check_reopen(std_ev) +#endif + +/* + create a std_event_context structure. +*/ +static int std_event_context_init(struct event_context *ev) +{ + struct std_event_context *std_ev; + + std_ev = talloc_zero(ev, struct std_event_context); + if (!std_ev) return -1; + std_ev->ev = ev; + std_ev->epoll_fd = -1; + + epoll_init_ctx(std_ev); + + ev->additional_data = std_ev; + return 0; +} + +/* + recalculate the maxfd +*/ +static void calc_maxfd(struct std_event_context *std_ev) +{ + struct fd_event *fde; + + std_ev->maxfd = 0; + for (fde = std_ev->fd_events; fde; fde = fde->next) { + if (fde->fd > std_ev->maxfd) { + std_ev->maxfd = fde->fd; + } + } +} + + +/* to mark the ev->maxfd invalid + * this means we need to recalculate it + */ +#define EVENT_INVALID_MAXFD (-1) + +/* + destroy an fd_event +*/ +static int std_event_fd_destructor(struct fd_event *fde) +{ + struct event_context *ev = fde->event_ctx; + struct std_event_context *std_ev = talloc_get_type(ev->additional_data, + struct std_event_context); + + epoll_check_reopen(std_ev); + + if (std_ev->maxfd == fde->fd) { + std_ev->maxfd = EVENT_INVALID_MAXFD; + } + + DLIST_REMOVE(std_ev->fd_events, fde); + std_ev->destruction_count++; + + epoll_del_event(std_ev, fde); + + if (fde->flags & EVENT_FD_AUTOCLOSE) { + close(fde->fd); + fde->fd = -1; + } + + return 0; +} + +/* + add a fd based event + return NULL on failure (memory allocation error) +*/ +static struct fd_event *std_event_add_fd(struct event_context *ev, TALLOC_CTX *mem_ctx, + int fd, uint16_t flags, + event_fd_handler_t handler, + void *private_data) +{ + struct std_event_context *std_ev = talloc_get_type(ev->additional_data, + struct std_event_context); + struct fd_event *fde; + + epoll_check_reopen(std_ev); + + fde = talloc(mem_ctx?mem_ctx:ev, struct fd_event); + if (!fde) return NULL; + + fde->event_ctx = ev; + fde->fd = fd; + fde->flags = flags; + fde->handler = handler; + fde->private_data = private_data; + fde->additional_flags = 0; + fde->additional_data = NULL; + + DLIST_ADD(std_ev->fd_events, fde); + if ((std_ev->maxfd != EVENT_INVALID_MAXFD) + && (fde->fd > std_ev->maxfd)) { + std_ev->maxfd = fde->fd; + } + talloc_set_destructor(fde, std_event_fd_destructor); + + epoll_add_event(std_ev, fde); + + return fde; +} + + +/* + return the fd event flags +*/ +static uint16_t std_event_get_fd_flags(struct fd_event *fde) +{ + return fde->flags; +} + +/* + set the fd event flags +*/ +static void std_event_set_fd_flags(struct fd_event *fde, uint16_t flags) +{ + struct event_context *ev; + struct std_event_context *std_ev; + + if (fde->flags == flags) return; + + ev = fde->event_ctx; + std_ev = talloc_get_type(ev->additional_data, struct std_event_context); + + fde->flags = flags; + + epoll_check_reopen(std_ev); + + epoll_change_event(std_ev, fde); +} + +/* + event loop handling using select() +*/ +static int std_event_loop_select(struct std_event_context *std_ev, struct timeval *tvalp) +{ + fd_set r_fds, w_fds; + struct fd_event *fde; + int selrtn; + uint32_t destruction_count = ++std_ev->destruction_count; + + /* we maybe need to recalculate the maxfd */ + if (std_ev->maxfd == EVENT_INVALID_MAXFD) { + calc_maxfd(std_ev); + } + + FD_ZERO(&r_fds); + FD_ZERO(&w_fds); + + /* setup any fd events */ + for (fde = std_ev->fd_events; fde; fde = fde->next) { + if (fde->flags & EVENT_FD_READ) { + FD_SET(fde->fd, &r_fds); + } + if (fde->flags & EVENT_FD_WRITE) { + FD_SET(fde->fd, &w_fds); + } + } + + if (std_ev->ev->num_signal_handlers && + common_event_check_signal(std_ev->ev)) { + return 0; + } + + selrtn = select(std_ev->maxfd+1, &r_fds, &w_fds, NULL, tvalp); + + if (selrtn == -1 && errno == EINTR && + std_ev->ev->num_signal_handlers) { + common_event_check_signal(std_ev->ev); + return 0; + } + + if (selrtn == -1 && errno == EBADF) { + /* the socket is dead! this should never + happen as the socket should have first been + made readable and that should have removed + the event, so this must be a bug. This is a + fatal error. */ + ev_debug(std_ev->ev, EV_DEBUG_FATAL, + "ERROR: EBADF on std_event_loop_once\n"); + std_ev->exit_code = EBADF; + return -1; + } + + if (selrtn == 0 && tvalp) { + /* we don't care about a possible delay here */ + common_event_loop_timer_delay(std_ev->ev); + return 0; + } + + if (selrtn > 0) { + /* at least one file descriptor is ready - check + which ones and call the handler, being careful to allow + the handler to remove itself when called */ + for (fde = std_ev->fd_events; fde; fde = fde->next) { + uint16_t flags = 0; + + if (FD_ISSET(fde->fd, &r_fds)) flags |= EVENT_FD_READ; + if (FD_ISSET(fde->fd, &w_fds)) flags |= EVENT_FD_WRITE; + if (flags) { + fde->handler(std_ev->ev, fde, flags, fde->private_data); + if (destruction_count != std_ev->destruction_count) { + break; + } + } + } + } + + return 0; +} + +/* + do a single event loop using the events defined in ev +*/ +static int std_event_loop_once(struct event_context *ev) +{ + struct std_event_context *std_ev = talloc_get_type(ev->additional_data, + struct std_event_context); + struct timeval tval; + + tval = common_event_loop_timer_delay(ev); + if (ev_timeval_is_zero(&tval)) { + return 0; + } + + epoll_check_reopen(std_ev); + + if (epoll_event_loop(std_ev, &tval) == 0) { + return 0; + } + + return std_event_loop_select(std_ev, &tval); +} + +/* + return on failure or (with 0) if all fd events are removed +*/ +static int std_event_loop_wait(struct event_context *ev) +{ + struct std_event_context *std_ev = talloc_get_type(ev->additional_data, + struct std_event_context); + std_ev->exit_code = 0; + + while (std_ev->fd_events && std_ev->exit_code == 0) { + if (std_event_loop_once(ev) != 0) { + break; + } + } + + return std_ev->exit_code; +} + +static const struct event_ops std_event_ops = { + .context_init = std_event_context_init, + .add_fd = std_event_add_fd, + .get_fd_flags = std_event_get_fd_flags, + .set_fd_flags = std_event_set_fd_flags, + .add_timed = common_event_add_timed, + .add_signal = common_event_add_signal, + .loop_once = std_event_loop_once, + .loop_wait = std_event_loop_wait, +}; + + +bool events_standard_init(void) +{ + return event_register_backend("standard", &std_event_ops); +} + diff --git a/lib/tevent/tevent_timed.c b/lib/tevent/tevent_timed.c new file mode 100644 index 0000000000..ba8213710e --- /dev/null +++ b/lib/tevent/tevent_timed.c @@ -0,0 +1,230 @@ +/* + Unix SMB/CIFS implementation. + + common events code for timed events + + Copyright (C) Andrew Tridgell 2003-2006 + Copyright (C) Stefan Metzmacher 2005 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include <sys/time.h> +#include <time.h> +#include "replace.h" +#include "system/filesys.h" +#include "system/select.h" +#include "tevent.h" +#include "tevent_internal.h" +#include "tevent_util.h" + +/** + compare two timeval structures. + Return -1 if tv1 < tv2 + Return 0 if tv1 == tv2 + Return 1 if tv1 > tv2 +*/ +static int ev_timeval_compare(const struct timeval *tv1, const struct timeval *tv2) +{ + if (tv1->tv_sec > tv2->tv_sec) return 1; + if (tv1->tv_sec < tv2->tv_sec) return -1; + if (tv1->tv_usec > tv2->tv_usec) return 1; + if (tv1->tv_usec < tv2->tv_usec) return -1; + return 0; +} + +/** + return a zero timeval +*/ +static struct timeval ev_timeval_zero(void) +{ + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 0; + return tv; +} + +/** + return a timeval for the current time +*/ +static struct timeval ev_timeval_current(void) +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return tv; +} + +/** + return a timeval struct with the given elements +*/ +static struct timeval ev_timeval_set(uint32_t secs, uint32_t usecs) +{ + struct timeval tv; + tv.tv_sec = secs; + tv.tv_usec = usecs; + return tv; +} + +/** + return the difference between two timevals as a timeval + if tv1 comes after tv2, then return a zero timeval + (this is *tv2 - *tv1) +*/ +static struct timeval ev_timeval_until(const struct timeval *tv1, + const struct timeval *tv2) +{ + struct timeval t; + if (ev_timeval_compare(tv1, tv2) >= 0) { + return ev_timeval_zero(); + } + t.tv_sec = tv2->tv_sec - tv1->tv_sec; + if (tv1->tv_usec > tv2->tv_usec) { + t.tv_sec--; + t.tv_usec = 1000000 - (tv1->tv_usec - tv2->tv_usec); + } else { + t.tv_usec = tv2->tv_usec - tv1->tv_usec; + } + return t; +} + +/** + return true if a timeval is zero +*/ +bool ev_timeval_is_zero(const struct timeval *tv) +{ + return tv->tv_sec == 0 && tv->tv_usec == 0; +} + +/* + destroy a timed event +*/ +static int common_event_timed_destructor(struct timed_event *te) +{ + struct event_context *ev = talloc_get_type(te->event_ctx, + struct event_context); + DLIST_REMOVE(ev->timed_events, te); + return 0; +} + +static int common_event_timed_deny_destructor(struct timed_event *te) +{ + return -1; +} + +/* + add a timed event + return NULL on failure (memory allocation error) +*/ +struct timed_event *common_event_add_timed(struct event_context *ev, TALLOC_CTX *mem_ctx, + struct timeval next_event, + event_timed_handler_t handler, + void *private_data) +{ + struct timed_event *te, *last_te, *cur_te; + + te = talloc(mem_ctx?mem_ctx:ev, struct timed_event); + if (te == NULL) return NULL; + + te->event_ctx = ev; + te->next_event = next_event; + te->handler = handler; + te->private_data = private_data; + te->additional_data = NULL; + + /* keep the list ordered */ + last_te = NULL; + for (cur_te = ev->timed_events; cur_te; cur_te = cur_te->next) { + /* if the new event comes before the current one break */ + if (ev_timeval_compare(&te->next_event, &cur_te->next_event) < 0) { + break; + } + + last_te = cur_te; + } + + DLIST_ADD_AFTER(ev->timed_events, te, last_te); + + talloc_set_destructor(te, common_event_timed_destructor); + + return te; +} + +/* + do a single event loop using the events defined in ev + + return the delay untill the next timed event, + or zero if a timed event was triggered +*/ +struct timeval common_event_loop_timer_delay(struct event_context *ev) +{ + struct timeval current_time = ev_timeval_zero(); + struct timed_event *te = ev->timed_events; + + if (!te) { + /* have a default tick time of 30 seconds. This guarantees + that code that uses its own timeout checking will be + able to proceeed eventually */ + return ev_timeval_set(30, 0); + } + + /* + * work out the right timeout for the next timed event + * + * avoid the syscall to gettimeofday() if the timed event should + * be triggered directly + * + * if there's a delay till the next timed event, we're done + * with just returning the delay + */ + if (!ev_timeval_is_zero(&te->next_event)) { + struct timeval delay; + + current_time = ev_timeval_current(); + + delay = ev_timeval_until(¤t_time, &te->next_event); + if (!ev_timeval_is_zero(&delay)) { + return delay; + } + } + + /* + * ok, we have a timed event that we'll process ... + */ + + /* deny the handler to free the event */ + talloc_set_destructor(te, common_event_timed_deny_destructor); + + /* We need to remove the timer from the list before calling the + * handler because in a semi-async inner event loop called from the + * handler we don't want to come across this event again -- vl */ + DLIST_REMOVE(ev->timed_events, te); + + /* + * If the timed event was registered for a zero current_time, + * then we pass a zero timeval here too! To avoid the + * overhead of gettimeofday() calls. + * + * otherwise we pass the current time + */ + te->handler(ev, te, current_time, te->private_data); + + /* The destructor isn't necessary anymore, we've already removed the + * event from the list. */ + talloc_set_destructor(te, NULL); + + talloc_free(te); + + return ev_timeval_zero(); +} + diff --git a/lib/tevent/tevent_util.c b/lib/tevent/tevent_util.c new file mode 100644 index 0000000000..cfcca9185d --- /dev/null +++ b/lib/tevent/tevent_util.c @@ -0,0 +1,86 @@ +/* + Unix SMB/CIFS implementation. + + Copyright (C) Andrew Tridgell 2005 + Copyright (C) Jelmer Vernooij 2005 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "replace.h" +#include "talloc.h" +#include "tevent.h" +#include "tevent_internal.h" +#include "tevent_util.h" +#include <fcntl.h> + +/** + return the number of elements in a string list +*/ +static size_t str_list_length(const char **list) +{ + size_t ret; + for (ret=0;list && list[ret];ret++) /* noop */ ; + return ret; +} + +/** + add an entry to a string list +*/ +const char **ev_str_list_add(const char **list, const char *s) +{ + size_t len = str_list_length(list); + const char **ret; + + ret = talloc_realloc(NULL, list, const char *, len+2); + if (ret == NULL) return NULL; + + ret[len] = talloc_strdup(ret, s); + if (ret[len] == NULL) return NULL; + + ret[len+1] = NULL; + + return ret; +} + + +/** + Set a fd into blocking/nonblocking mode. Uses POSIX O_NONBLOCK if available, + else + if SYSV use O_NDELAY + if BSD use FNDELAY +**/ + +int ev_set_blocking(int fd, bool set) +{ + int val; +#ifdef O_NONBLOCK +#define FLAG_TO_SET O_NONBLOCK +#else +#ifdef SYSV +#define FLAG_TO_SET O_NDELAY +#else /* BSD */ +#define FLAG_TO_SET FNDELAY +#endif +#endif + + if((val = fcntl(fd, F_GETFL, 0)) == -1) + return -1; + if(set) /* Turn blocking on - ie. clear nonblock flag */ + val &= ~FLAG_TO_SET; + else + val |= FLAG_TO_SET; + return fcntl( fd, F_SETFL, val); +#undef FLAG_TO_SET +} diff --git a/lib/tevent/tevent_util.h b/lib/tevent/tevent_util.h new file mode 100644 index 0000000000..052b302aae --- /dev/null +++ b/lib/tevent/tevent_util.h @@ -0,0 +1,117 @@ +/* + Unix SMB/CIFS implementation. + + Copyright (C) Andrew Tridgell 1998-2005 + Copyright (C) Jelmer Vernooij 2005 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +/* To use these macros you must have a structure containing a next and + prev pointer */ + +#ifndef _DLINKLIST_H +#define _DLINKLIST_H + + +/* hook into the front of the list */ +#define DLIST_ADD(list, p) \ +do { \ + if (!(list)) { \ + (list) = (p); \ + (p)->next = (p)->prev = NULL; \ + } else { \ + (list)->prev = (p); \ + (p)->next = (list); \ + (p)->prev = NULL; \ + (list) = (p); \ + }\ +} while (0) + +/* remove an element from a list - element doesn't have to be in list. */ +#define DLIST_REMOVE(list, p) \ +do { \ + if ((p) == (list)) { \ + (list) = (p)->next; \ + if (list) (list)->prev = NULL; \ + } else { \ + if ((p)->prev) (p)->prev->next = (p)->next; \ + if ((p)->next) (p)->next->prev = (p)->prev; \ + } \ + if ((p) != (list)) (p)->next = (p)->prev = NULL; \ +} while (0) + +/* promote an element to the top of the list */ +#define DLIST_PROMOTE(list, p) \ +do { \ + DLIST_REMOVE(list, p); \ + DLIST_ADD(list, p); \ +} while (0) + +/* hook into the end of the list - needs a tmp pointer */ +#define DLIST_ADD_END(list, p, type) \ +do { \ + if (!(list)) { \ + (list) = (p); \ + (p)->next = (p)->prev = NULL; \ + } else { \ + type tmp; \ + for (tmp = (list); tmp->next; tmp = tmp->next) ; \ + tmp->next = (p); \ + (p)->next = NULL; \ + (p)->prev = tmp; \ + } \ +} while (0) + +/* insert 'p' after the given element 'el' in a list. If el is NULL then + this is the same as a DLIST_ADD() */ +#define DLIST_ADD_AFTER(list, p, el) \ +do { \ + if (!(list) || !(el)) { \ + DLIST_ADD(list, p); \ + } else { \ + p->prev = el; \ + p->next = el->next; \ + el->next = p; \ + if (p->next) p->next->prev = p; \ + }\ +} while (0) + +/* demote an element to the end of the list, needs a tmp pointer */ +#define DLIST_DEMOTE(list, p, tmp) \ +do { \ + DLIST_REMOVE(list, p); \ + DLIST_ADD_END(list, p, tmp); \ +} while (0) + +/* concatenate two lists - putting all elements of the 2nd list at the + end of the first list */ +#define DLIST_CONCATENATE(list1, list2, type) \ +do { \ + if (!(list1)) { \ + (list1) = (list2); \ + } else { \ + type tmp; \ + for (tmp = (list1); tmp->next; tmp = tmp->next) ; \ + tmp->next = (list2); \ + if (list2) { \ + (list2)->prev = tmp; \ + } \ + } \ +} while (0) + +#endif /* _DLINKLIST_H */ + +const char **ev_str_list_add(const char **list, const char *s); +int ev_set_blocking(int fd, bool set); diff --git a/lib/util/debug.h b/lib/util/debug.h index a5962b04bb..7518a64e19 100644 --- a/lib/util/debug.h +++ b/lib/util/debug.h @@ -133,6 +133,7 @@ _PUBLIC_ void register_debug_handlers(const char *name, struct debug_ops *ops); */ _PUBLIC_ void dbgtext(const char *format, ...) PRINTF_ATTRIBUTE(1,2); -extern XFILE *dbf; +struct _XFILE; +extern struct _XFILE *dbf; #endif diff --git a/lib/util/xfile.h b/lib/util/xfile.h index af90f3f55c..1b15929997 100644 --- a/lib/util/xfile.h +++ b/lib/util/xfile.h @@ -23,7 +23,7 @@ see xfile.c for explanations */ -typedef struct { +typedef struct _XFILE { int fd; char *buf; char *next; |