2 Unix SMB/CIFS implementation.
3 Python bindings for tevent
5 Copyright (C) Jelmer Vernooij 2010
7 ** NOTE! The following LGPL license applies to the tevent
8 ** library. This does NOT imply that all of Samba is released
11 This library is free software; you can redistribute it and/or
12 modify it under the terms of the GNU Lesser General Public
13 License as published by the Free Software Foundation; either
14 version 3 of the License, or (at your option) any later version.
16 This library is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 Lesser General Public License for more details.
21 You should have received a copy of the GNU Lesser General Public
22 License along with this library; if not, see <http://www.gnu.org/licenses/>.
25 #include "lib/replace/system/python.h"
30 /* discard signature of 'func' in favour of 'target_sig' */
31 #define PY_DISCARD_FUNC_SIG(target_sig, func) (target_sig)(void(*)(void))func
33 void init_tevent(void);
37 struct tevent_context
*ev
;
38 } TeventContext_Object
;
42 struct tevent_queue
*queue
;
47 struct tevent_req
*req
;
52 struct tevent_signal
*signal
;
53 } TeventSignal_Object
;
57 struct tevent_timer
*timer
;
66 static PyTypeObject TeventContext_Type
;
67 static PyTypeObject TeventReq_Type
;
68 static PyTypeObject TeventQueue_Type
;
69 static PyTypeObject TeventSignal_Type
;
70 static PyTypeObject TeventTimer_Type
;
71 static PyTypeObject TeventFd_Type
;
73 static PyObject
*py_tevent_context_reinitialise(TeventContext_Object
*self
,
74 PyObject
*Py_UNUSED(ignored
))
76 int ret
= tevent_re_initialise(self
->ev
);
78 PyErr_SetNone(PyExc_RuntimeError
);
84 static PyObject
*py_tevent_queue_stop(TeventQueue_Object
*self
,
85 PyObject
*Py_UNUSED(ignored
))
87 tevent_queue_stop(self
->queue
);
91 static PyObject
*py_tevent_queue_start(TeventQueue_Object
*self
,
92 PyObject
*Py_UNUSED(ignored
))
94 tevent_queue_start(self
->queue
);
98 static void py_queue_trigger(struct tevent_req
*req
, void *private_data
)
100 PyObject
*callback
= private_data
, *ret
;
102 ret
= PyObject_CallFunction(callback
, discard_const_p(char, ""));
106 static PyObject
*py_tevent_queue_add(TeventQueue_Object
*self
, PyObject
*args
)
108 TeventContext_Object
*py_ev
;
109 TeventReq_Object
*py_req
;
113 if (!PyArg_ParseTuple(args
, "O!O!O",
114 &TeventContext_Type
, &py_ev
,
115 &TeventReq_Type
, &py_req
,
121 ret
= tevent_queue_add(self
->queue
, py_ev
->ev
, py_req
->req
,
122 py_queue_trigger
, trigger
);
124 PyErr_SetString(PyExc_RuntimeError
, "queue add failed");
132 static PyMethodDef py_tevent_queue_methods
[] = {
133 { "stop", (PyCFunction
)py_tevent_queue_stop
,
136 { "start", (PyCFunction
)py_tevent_queue_start
,
139 { "add", (PyCFunction
)py_tevent_queue_add
, METH_VARARGS
,
140 "S.add(ctx, req, trigger, baton)" },
144 static PyObject
*py_tevent_context_wakeup_send(PyObject
*self
, PyObject
*args
)
151 static PyObject
*py_tevent_context_loop_wait(TeventContext_Object
*self
,
152 PyObject
*Py_UNUSED(ignored
))
154 if (tevent_loop_wait(self
->ev
) != 0) {
155 PyErr_SetNone(PyExc_RuntimeError
);
161 static PyObject
*py_tevent_context_loop_once(TeventContext_Object
*self
,
162 PyObject
*Py_UNUSED(ignored
))
164 if (tevent_loop_once(self
->ev
) != 0) {
165 PyErr_SetNone(PyExc_RuntimeError
);
171 static void py_tevent_signal_handler(struct tevent_context
*ev
,
172 struct tevent_signal
*se
,
178 PyObject
*callback
= (PyObject
*)private_data
, *ret
;
180 ret
= PyObject_CallFunction(callback
, discard_const_p(char, "ii"), signum
, count
);
184 static void py_tevent_signal_dealloc(TeventSignal_Object
*self
)
186 talloc_free(self
->signal
);
190 static PyTypeObject TeventSignal_Type
= {
191 .tp_name
= "tevent.Signal",
192 .tp_basicsize
= sizeof(TeventSignal_Object
),
193 .tp_dealloc
= (destructor
)py_tevent_signal_dealloc
,
194 .tp_flags
= Py_TPFLAGS_DEFAULT
,
197 static PyObject
*py_tevent_context_add_signal(TeventContext_Object
*self
, PyObject
*args
)
199 int signum
, sa_flags
;
201 struct tevent_signal
*sig
;
202 TeventSignal_Object
*ret
;
204 if (!PyArg_ParseTuple(args
, "iiO", &signum
, &sa_flags
, &handler
))
208 sig
= tevent_add_signal(self
->ev
, NULL
, signum
, sa_flags
,
209 py_tevent_signal_handler
, handler
);
211 ret
= PyObject_New(TeventSignal_Object
, &TeventSignal_Type
);
220 return (PyObject
*)ret
;
223 static void py_timer_handler(struct tevent_context
*ev
,
224 struct tevent_timer
*te
,
225 struct timeval current_time
,
228 TeventTimer_Object
*self
= private_data
;
231 ret
= PyObject_CallFunction(self
->callback
, discard_const_p(char, "l"), te
);
233 /* No Python stack to propagate exception to; just print traceback */
239 static void py_tevent_timer_dealloc(TeventTimer_Object
*self
)
242 talloc_free(self
->timer
);
244 Py_CLEAR(self
->callback
);
248 static int py_tevent_timer_traverse(TeventTimer_Object
*self
, visitproc visit
, void *arg
)
250 Py_VISIT(self
->callback
);
254 static PyObject
* py_tevent_timer_get_active(TeventTimer_Object
*self
,
255 PyObject
*Py_UNUSED(ignored
))
257 return PyBool_FromLong(self
->timer
!= NULL
);
260 struct PyGetSetDef py_tevent_timer_getset
[] = {
262 .name
= discard_const_p(char, "active"),
263 .get
= (getter
)py_tevent_timer_get_active
,
264 .doc
= discard_const_p(char, "true if the timer is scheduled to run"),
269 static PyTypeObject TeventTimer_Type
= {
270 .tp_name
= "tevent.Timer",
271 .tp_basicsize
= sizeof(TeventTimer_Object
),
272 .tp_dealloc
= (destructor
)py_tevent_timer_dealloc
,
273 .tp_traverse
= (traverseproc
)py_tevent_timer_traverse
,
274 .tp_getset
= py_tevent_timer_getset
,
275 .tp_flags
= Py_TPFLAGS_DEFAULT
,
278 struct TeventTimer_Object_ref
{
279 TeventTimer_Object
*obj
;
282 static int TeventTimer_Object_ref_destructor(struct TeventTimer_Object_ref
*ref
)
284 ref
->obj
->timer
= NULL
;
289 static PyObject
*py_tevent_context_add_timer_internal(TeventContext_Object
*self
,
290 struct timeval next_event
,
295 * There are 5 pieces in play; two tevent contexts and 3 Python objects:
297 * - The tevent context
298 * - The Python context -- "self"
299 * - The Python timer (TeventTimer_Object) -- "ret"
300 * - The Python callback function -- "callback"
302 * We only use the Python context for getting the tevent context,
303 * afterwards it can be destroyed.
305 * The tevent context owns the tevent timer.
307 * The tevent timer holds a reference to the Python timer, so the Python
308 * timer must always outlive the tevent timer.
309 * The Python timer has a pointer to the tevent timer; a destructor is
310 * used to set this to NULL when the tevent timer is deallocated.
312 * The tevent timer can be deallocated in these cases:
313 * 1) when the context is destroyed
314 * 2) after the event fires
315 * Posssibly, API might be added to cancel (free the tevent timer).
317 * The Python timer holds a reference to the callback.
319 TeventTimer_Object
*ret
;
320 struct TeventTimer_Object_ref
*ref
;
322 ret
= PyObject_New(TeventTimer_Object
, &TeventTimer_Type
);
328 ret
->callback
= callback
;
329 ret
->timer
= tevent_add_timer(self
->ev
, NULL
, next_event
, py_timer_handler
,
331 if (ret
->timer
== NULL
) {
333 PyErr_SetString(PyExc_RuntimeError
, "Could not initialize timer");
336 ref
= talloc(ret
->timer
, struct TeventTimer_Object_ref
);
338 talloc_free(ret
->timer
);
340 PyErr_SetString(PyExc_RuntimeError
, "Could not initialize timer");
346 talloc_set_destructor(ref
, TeventTimer_Object_ref_destructor
);
348 return (PyObject
*)ret
;
351 static PyObject
*py_tevent_context_add_timer(TeventContext_Object
*self
, PyObject
*args
)
353 struct timeval next_event
;
356 if (!PyArg_ParseTuple(args
, "dO", &secs
, &callback
)){
359 next_event
.tv_sec
= secs
;
360 usecs
= (secs
- next_event
.tv_sec
) * 1000000.0;
361 next_event
.tv_usec
= usecs
;
362 return py_tevent_context_add_timer_internal(self
, next_event
, callback
);
365 static PyObject
*py_tevent_context_add_timer_offset(TeventContext_Object
*self
, PyObject
*args
)
367 struct timeval next_event
;
371 if (!PyArg_ParseTuple(args
, "dO", &offset
, &callback
))
376 next_event
= tevent_timeval_current_ofs(seconds
, (int)(offset
*1000000));
377 return py_tevent_context_add_timer_internal(self
, next_event
, callback
);
380 static void py_fd_handler(struct tevent_context
*ev
,
381 struct tevent_fd
*fde
,
385 PyObject
*callback
= private_data
, *ret
;
387 ret
= PyObject_CallFunction(callback
, discard_const_p(char, "i"), flags
);
391 static void py_tevent_fp_dealloc(TeventFd_Object
*self
)
393 talloc_free(self
->fd
);
397 static PyTypeObject TeventFd_Type
= {
398 .tp_name
= "tevent.Fd",
399 .tp_basicsize
= sizeof(TeventFd_Object
),
400 .tp_dealloc
= (destructor
)py_tevent_fp_dealloc
,
401 .tp_flags
= Py_TPFLAGS_DEFAULT
,
404 static PyObject
*py_tevent_context_add_fd(TeventContext_Object
*self
, PyObject
*args
)
408 struct tevent_fd
*tfd
;
409 TeventFd_Object
*ret
;
411 if (!PyArg_ParseTuple(args
, "iiO", &fd
, &flags
, &handler
))
414 tfd
= tevent_add_fd(self
->ev
, NULL
, fd
, flags
, py_fd_handler
, handler
);
416 PyErr_SetNone(PyExc_RuntimeError
);
420 ret
= PyObject_New(TeventFd_Object
, &TeventFd_Type
);
427 return (PyObject
*)ret
;
430 static PyMethodDef py_tevent_context_methods
[] = {
431 { "reinitialise", (PyCFunction
)py_tevent_context_reinitialise
,
433 "S.reinitialise()" },
434 { "wakeup_send", (PyCFunction
)py_tevent_context_wakeup_send
,
435 METH_VARARGS
, "S.wakeup_send(wakeup_time) -> req" },
436 { "loop_wait", (PyCFunction
)py_tevent_context_loop_wait
,
437 METH_NOARGS
, "S.loop_wait()" },
438 { "loop_once", (PyCFunction
)py_tevent_context_loop_once
,
439 METH_NOARGS
, "S.loop_once()" },
440 { "add_signal", (PyCFunction
)py_tevent_context_add_signal
,
441 METH_VARARGS
, "S.add_signal(signum, sa_flags, handler) -> signal" },
442 { "add_timer", (PyCFunction
)py_tevent_context_add_timer
,
443 METH_VARARGS
, "S.add_timer(next_event, handler) -> timer" },
444 { "add_timer_offset", (PyCFunction
)py_tevent_context_add_timer_offset
,
445 METH_VARARGS
, "S.add_timer_offset(offset_seconds, handler) -> timer" },
446 { "add_fd", (PyCFunction
)py_tevent_context_add_fd
,
447 METH_VARARGS
, "S.add_fd(fd, flags, handler) -> fd" },
451 static PyObject
*py_tevent_req_wakeup_recv(PyObject
*self
,
452 PyObject
*Py_UNUSED(ignored
))
458 static PyObject
*py_tevent_req_received(PyObject
*self
,
459 PyObject
*Py_UNUSED(ignored
))
465 static PyObject
*py_tevent_req_is_error(PyObject
*self
,
466 PyObject
*Py_UNUSED(ignored
))
472 static PyObject
*py_tevent_req_poll(PyObject
*self
,
473 PyObject
*Py_UNUSED(ignored
))
479 static PyObject
*py_tevent_req_is_in_progress(PyObject
*self
,
480 PyObject
*Py_UNUSED(ignored
))
486 static PyGetSetDef py_tevent_req_getsetters
[] = {
488 .name
= discard_const_p(char, "in_progress"),
489 .get
= (getter
)py_tevent_req_is_in_progress
,
490 .doc
= discard_const_p(char, "Whether the request is in progress"),
495 static PyObject
*py_tevent_req_post(PyObject
*self
, PyObject
*args
)
501 static PyObject
*py_tevent_req_set_error(PyObject
*self
, PyObject
*args
)
507 static PyObject
*py_tevent_req_done(PyObject
*self
,
508 PyObject
*Py_UNUSED(ignored
))
514 static PyObject
*py_tevent_req_notify_callback(PyObject
*self
,
515 PyObject
*Py_UNUSED(ignored
))
521 static PyObject
*py_tevent_req_set_endtime(PyObject
*self
, PyObject
*args
)
527 static PyObject
*py_tevent_req_cancel(TeventReq_Object
*self
,
528 PyObject
*Py_UNUSED(ignored
))
530 if (!tevent_req_cancel(self
->req
)) {
531 PyErr_SetNone(PyExc_RuntimeError
);
537 static PyMethodDef py_tevent_req_methods
[] = {
538 { "wakeup_recv", (PyCFunction
)py_tevent_req_wakeup_recv
,
541 { "received", (PyCFunction
)py_tevent_req_received
,
543 "Receive finished" },
544 { "is_error", (PyCFunction
)py_tevent_req_is_error
, METH_NOARGS
,
545 "is_error() -> (error, state)" },
546 { "poll", (PyCFunction
)py_tevent_req_poll
, METH_VARARGS
,
548 { "post", (PyCFunction
)py_tevent_req_post
, METH_VARARGS
,
549 "post(ctx) -> req" },
550 { "set_error", (PyCFunction
)py_tevent_req_set_error
, METH_VARARGS
,
551 "set_error(error)" },
552 { "done", (PyCFunction
)py_tevent_req_done
, METH_NOARGS
,
554 { "notify_callback", (PyCFunction
)py_tevent_req_notify_callback
,
555 METH_NOARGS
, "notify_callback()" },
556 { "set_endtime", (PyCFunction
)py_tevent_req_set_endtime
,
557 METH_VARARGS
, "set_endtime(ctx, endtime)" },
558 { "cancel", (PyCFunction
)py_tevent_req_cancel
,
559 METH_NOARGS
, "cancel()" },
563 static void py_tevent_req_dealloc(TeventReq_Object
*self
)
565 talloc_free(self
->req
);
569 static PyTypeObject TeventReq_Type
= {
570 .tp_name
= "tevent.Request",
571 .tp_basicsize
= sizeof(TeventReq_Object
),
572 .tp_methods
= py_tevent_req_methods
,
573 .tp_dealloc
= (destructor
)py_tevent_req_dealloc
,
574 .tp_getset
= py_tevent_req_getsetters
,
575 /* FIXME: .tp_new = py_tevent_req_new, */
578 static PyObject
*py_tevent_queue_get_length(TeventQueue_Object
*self
,
579 PyObject
*Py_UNUSED(ignored
))
581 return PyLong_FromLong(tevent_queue_length(self
->queue
));
584 static PyGetSetDef py_tevent_queue_getsetters
[] = {
586 .name
= discard_const_p(char, "length"),
587 .get
= (getter
)py_tevent_queue_get_length
,
588 .doc
= discard_const_p(char, "The number of elements in the queue."),
593 static void py_tevent_queue_dealloc(TeventQueue_Object
*self
)
595 talloc_free(self
->queue
);
599 static PyTypeObject TeventQueue_Type
= {
600 .tp_name
= "tevent.Queue",
601 .tp_basicsize
= sizeof(TeventQueue_Object
),
602 .tp_dealloc
= (destructor
)py_tevent_queue_dealloc
,
603 .tp_flags
= Py_TPFLAGS_DEFAULT
,
604 .tp_getset
= py_tevent_queue_getsetters
,
605 .tp_methods
= py_tevent_queue_methods
,
608 static PyObject
*py_tevent_context_signal_support(PyObject
*_self
,
609 PyObject
*Py_UNUSED(ignored
))
611 TeventContext_Object
*self
= (TeventContext_Object
*)_self
;
612 return PyBool_FromLong(tevent_signal_support(self
->ev
));
615 static PyGetSetDef py_tevent_context_getsetters
[] = {
617 .name
= discard_const_p(char, "signal_support"),
618 .get
= PY_DISCARD_FUNC_SIG(getter
,
619 py_tevent_context_signal_support
),
620 .doc
= discard_const_p(char, "if this platform and tevent context support signal handling"),
625 static void py_tevent_context_dealloc(TeventContext_Object
*self
)
627 talloc_free(self
->ev
);
631 static PyObject
*py_tevent_context_new(PyTypeObject
*type
, PyObject
*args
, PyObject
*kwargs
)
633 const char * const kwnames
[] = { "name", NULL
};
635 struct tevent_context
*ev
;
636 TeventContext_Object
*ret
;
638 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "|s", discard_const_p(char *, kwnames
), &name
))
642 ev
= tevent_context_init(NULL
);
644 ev
= tevent_context_init_byname(NULL
, name
);
648 PyErr_SetNone(PyExc_RuntimeError
);
652 ret
= PyObject_New(TeventContext_Object
, type
);
660 return (PyObject
*)ret
;
663 static PyTypeObject TeventContext_Type
= {
664 .tp_name
= "tevent.Context",
665 .tp_new
= py_tevent_context_new
,
666 .tp_basicsize
= sizeof(TeventContext_Object
),
667 .tp_dealloc
= (destructor
)py_tevent_context_dealloc
,
668 .tp_methods
= py_tevent_context_methods
,
669 .tp_getset
= py_tevent_context_getsetters
,
670 .tp_flags
= Py_TPFLAGS_DEFAULT
,
673 static PyObject
*py_set_default_backend(PyObject
*self
, PyObject
*args
)
676 if (!PyArg_ParseTuple(args
, "s", &backend_name
))
679 tevent_set_default_backend(backend_name
);
684 static PyObject
*py_backend_list(PyObject
*self
,
685 PyObject
*Py_UNUSED(ignored
))
687 PyObject
*ret
= NULL
;
688 PyObject
*string
= NULL
;
690 const char **backends
= NULL
;
697 backends
= tevent_backend_list(NULL
);
698 if (backends
== NULL
) {
699 PyErr_SetNone(PyExc_RuntimeError
);
702 for (i
= 0; backends
[i
]; i
++) {
703 string
= PyUnicode_FromString(backends
[i
]);
707 result
= PyList_Append(ret
, string
);
715 talloc_free(backends
);
722 talloc_free(backends
);
726 static PyMethodDef tevent_methods
[] = {
727 { "set_default_backend", (PyCFunction
)py_set_default_backend
,
728 METH_VARARGS
, "set_default_backend(backend)" },
729 { "backend_list", (PyCFunction
)py_backend_list
,
730 METH_NOARGS
, "backend_list() -> list" },
734 #define MODULE_DOC PyDoc_STR("Python wrapping of talloc-maintained objects.")
736 static struct PyModuleDef moduledef
= {
737 PyModuleDef_HEAD_INIT
,
741 .m_methods
= tevent_methods
,
744 PyObject
* module_init(void);
745 PyObject
* module_init(void)
749 if (PyType_Ready(&TeventContext_Type
) < 0)
752 if (PyType_Ready(&TeventQueue_Type
) < 0)
755 if (PyType_Ready(&TeventReq_Type
) < 0)
758 if (PyType_Ready(&TeventSignal_Type
) < 0)
761 if (PyType_Ready(&TeventTimer_Type
) < 0)
764 if (PyType_Ready(&TeventFd_Type
) < 0)
767 m
= PyModule_Create(&moduledef
);
771 Py_INCREF(&TeventContext_Type
);
772 PyModule_AddObject(m
, "Context", (PyObject
*)&TeventContext_Type
);
774 Py_INCREF(&TeventQueue_Type
);
775 PyModule_AddObject(m
, "Queue", (PyObject
*)&TeventQueue_Type
);
777 Py_INCREF(&TeventReq_Type
);
778 PyModule_AddObject(m
, "Request", (PyObject
*)&TeventReq_Type
);
780 Py_INCREF(&TeventSignal_Type
);
781 PyModule_AddObject(m
, "Signal", (PyObject
*)&TeventSignal_Type
);
783 Py_INCREF(&TeventTimer_Type
);
784 PyModule_AddObject(m
, "Timer", (PyObject
*)&TeventTimer_Type
);
786 Py_INCREF(&TeventFd_Type
);
787 PyModule_AddObject(m
, "Fd", (PyObject
*)&TeventFd_Type
);
789 PyModule_AddStringConstant(m
, "__version__", PACKAGE_VERSION
);
794 PyMODINIT_FUNC
PyInit__tevent(void);
795 PyMODINIT_FUNC
PyInit__tevent(void)
797 return module_init();