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/>.
29 #if PY_MAJOR_VERSION >= 3
30 #define PyStr_Check PyUnicode_Check
31 #define PyStr_FromString PyUnicode_FromString
32 #define PyStr_AsUTF8 PyUnicode_AsUTF8
33 #define PyInt_FromLong PyLong_FromLong
35 #define PyStr_Check PyString_Check
36 #define PyStr_FromString PyString_FromString
37 #define PyStr_AsUTF8 PyString_AsString
40 void init_tevent(void);
44 struct tevent_context
*ev
;
45 } TeventContext_Object
;
49 struct tevent_queue
*queue
;
54 struct tevent_req
*req
;
59 struct tevent_signal
*signal
;
60 } TeventSignal_Object
;
64 struct tevent_timer
*timer
;
73 static PyTypeObject TeventContext_Type
;
74 static PyTypeObject TeventReq_Type
;
75 static PyTypeObject TeventQueue_Type
;
76 static PyTypeObject TeventSignal_Type
;
77 static PyTypeObject TeventTimer_Type
;
78 static PyTypeObject TeventFd_Type
;
80 static int py_context_init(struct tevent_context
*ev
)
86 static struct tevent_fd
*py_add_fd(struct tevent_context
*ev
,
88 int fd
, uint16_t flags
,
89 tevent_fd_handler_t handler
,
91 const char *handler_name
,
98 static void py_set_fd_close_fn(struct tevent_fd
*fde
,
99 tevent_fd_close_fn_t close_fn
)
104 static uint16_t py_get_fd_flags(struct tevent_fd
*fde
)
110 static void py_set_fd_flags(struct tevent_fd
*fde
, uint16_t flags
)
115 /* timed_event functions */
116 static struct tevent_timer
*py_add_timer(struct tevent_context
*ev
,
118 struct timeval next_event
,
119 tevent_timer_handler_t handler
,
121 const char *handler_name
,
122 const char *location
)
128 /* immediate event functions */
129 static void py_schedule_immediate(struct tevent_immediate
*im
,
130 struct tevent_context
*ev
,
131 tevent_immediate_handler_t handler
,
133 const char *handler_name
,
134 const char *location
)
139 /* signal functions */
140 static struct tevent_signal
*py_add_signal(struct tevent_context
*ev
,
142 int signum
, int sa_flags
,
143 tevent_signal_handler_t handler
,
145 const char *handler_name
,
146 const char *location
)
153 static int py_loop_once(struct tevent_context
*ev
, const char *location
)
159 static int py_loop_wait(struct tevent_context
*ev
, const char *location
)
165 const static struct tevent_ops py_tevent_ops
= {
166 .context_init
= py_context_init
,
168 .set_fd_close_fn
= py_set_fd_close_fn
,
169 .get_fd_flags
= py_get_fd_flags
,
170 .set_fd_flags
= py_set_fd_flags
,
171 .add_timer
= py_add_timer
,
172 .schedule_immediate
= py_schedule_immediate
,
173 .add_signal
= py_add_signal
,
174 .loop_wait
= py_loop_wait
,
175 .loop_once
= py_loop_once
,
178 static PyObject
*py_register_backend(PyObject
*self
, PyObject
*args
)
180 PyObject
*name
, *py_backend
;
182 if (!PyArg_ParseTuple(args
, "O", &py_backend
))
185 name
= PyObject_GetAttrString(py_backend
, "name");
187 PyErr_SetNone(PyExc_AttributeError
);
191 if (!PyStr_Check(name
)) {
192 PyErr_SetNone(PyExc_TypeError
);
197 if (!tevent_register_backend(PyStr_AsUTF8(name
), &py_tevent_ops
)) { /* FIXME: What to do with backend */
198 PyErr_SetNone(PyExc_RuntimeError
);
208 static PyObject
*py_tevent_context_reinitialise(TeventContext_Object
*self
)
210 int ret
= tevent_re_initialise(self
->ev
);
212 PyErr_SetNone(PyExc_RuntimeError
);
218 static PyObject
*py_tevent_queue_stop(TeventQueue_Object
*self
)
220 tevent_queue_stop(self
->queue
);
224 static PyObject
*py_tevent_queue_start(TeventQueue_Object
*self
)
226 tevent_queue_start(self
->queue
);
230 static void py_queue_trigger(struct tevent_req
*req
, void *private_data
)
232 PyObject
*callback
= private_data
, *ret
;
234 ret
= PyObject_CallFunction(callback
, discard_const_p(char, ""));
238 static PyObject
*py_tevent_queue_add(TeventQueue_Object
*self
, PyObject
*args
)
240 TeventContext_Object
*py_ev
;
241 TeventReq_Object
*py_req
;
245 if (!PyArg_ParseTuple(args
, "O!O!O",
246 &TeventContext_Type
, &py_ev
,
247 &TeventReq_Type
, &py_req
,
253 ret
= tevent_queue_add(self
->queue
, py_ev
->ev
, py_req
->req
,
254 py_queue_trigger
, trigger
);
256 PyErr_SetString(PyExc_RuntimeError
, "queue add failed");
264 static PyMethodDef py_tevent_queue_methods
[] = {
265 { "stop", (PyCFunction
)py_tevent_queue_stop
, METH_NOARGS
,
267 { "start", (PyCFunction
)py_tevent_queue_start
, METH_NOARGS
,
269 { "add", (PyCFunction
)py_tevent_queue_add
, METH_VARARGS
,
270 "S.add(ctx, req, trigger, baton)" },
274 static PyObject
*py_tevent_context_wakeup_send(PyObject
*self
, PyObject
*args
)
281 static PyObject
*py_tevent_context_loop_wait(TeventContext_Object
*self
)
283 if (tevent_loop_wait(self
->ev
) != 0) {
284 PyErr_SetNone(PyExc_RuntimeError
);
290 static PyObject
*py_tevent_context_loop_once(TeventContext_Object
*self
)
292 if (tevent_loop_once(self
->ev
) != 0) {
293 PyErr_SetNone(PyExc_RuntimeError
);
299 static void py_tevent_signal_handler(struct tevent_context
*ev
,
300 struct tevent_signal
*se
,
306 PyObject
*callback
= (PyObject
*)private_data
, *ret
;
308 ret
= PyObject_CallFunction(callback
, discard_const_p(char, "ii"), signum
, count
);
312 static void py_tevent_signal_dealloc(TeventSignal_Object
*self
)
314 talloc_free(self
->signal
);
318 static PyTypeObject TeventSignal_Type
= {
319 .tp_name
= "tevent.Signal",
320 .tp_basicsize
= sizeof(TeventSignal_Object
),
321 .tp_dealloc
= (destructor
)py_tevent_signal_dealloc
,
322 .tp_flags
= Py_TPFLAGS_DEFAULT
,
325 static PyObject
*py_tevent_context_add_signal(TeventContext_Object
*self
, PyObject
*args
)
327 int signum
, sa_flags
;
329 struct tevent_signal
*sig
;
330 TeventSignal_Object
*ret
;
332 if (!PyArg_ParseTuple(args
, "iiO", &signum
, &sa_flags
, &handler
))
336 sig
= tevent_add_signal(self
->ev
, NULL
, signum
, sa_flags
,
337 py_tevent_signal_handler
, handler
);
339 ret
= PyObject_New(TeventSignal_Object
, &TeventSignal_Type
);
348 return (PyObject
*)ret
;
351 static void py_timer_handler(struct tevent_context
*ev
,
352 struct tevent_timer
*te
,
353 struct timeval current_time
,
356 TeventTimer_Object
*self
= private_data
;
359 ret
= PyObject_CallFunction(self
->callback
, discard_const_p(char, "l"), te
);
361 /* No Python stack to propagate exception to; just print traceback */
367 static void py_tevent_timer_dealloc(TeventTimer_Object
*self
)
370 talloc_free(self
->timer
);
372 Py_DECREF(self
->callback
);
376 static int py_tevent_timer_traverse(TeventTimer_Object
*self
, visitproc visit
, void *arg
)
378 Py_VISIT(self
->callback
);
382 static PyObject
* py_tevent_timer_get_active(TeventTimer_Object
*self
) {
383 return PyBool_FromLong(self
->timer
!= NULL
);
386 struct PyGetSetDef py_tevent_timer_getset
[] = {
388 .name
= discard_const_p(char, "active"),
389 .get
= (getter
)py_tevent_timer_get_active
,
390 .doc
= discard_const_p(char, "true if the timer is scheduled to run"),
395 static PyTypeObject TeventTimer_Type
= {
396 .tp_name
= "tevent.Timer",
397 .tp_basicsize
= sizeof(TeventTimer_Object
),
398 .tp_dealloc
= (destructor
)py_tevent_timer_dealloc
,
399 .tp_traverse
= (traverseproc
)py_tevent_timer_traverse
,
400 .tp_getset
= py_tevent_timer_getset
,
401 .tp_flags
= Py_TPFLAGS_DEFAULT
,
404 struct TeventTimer_Object_ref
{
405 TeventTimer_Object
*obj
;
408 static int TeventTimer_Object_ref_destructor(struct TeventTimer_Object_ref
*ref
)
410 ref
->obj
->timer
= NULL
;
415 static PyObject
*py_tevent_context_add_timer_internal(TeventContext_Object
*self
,
416 struct timeval next_event
,
421 * There are 5 pieces in play; two tevent contexts and 3 Python objects:
423 * - The tevent context
424 * - The Python context -- "self"
425 * - The Python timer (TeventTimer_Object) -- "ret"
426 * - The Python callback function -- "callback"
428 * We only use the Python context for getting the tevent context,
429 * afterwards it can be destroyed.
431 * The tevent context owns the tevent timer.
433 * The tevent timer holds a reference to the Python timer, so the Python
434 * timer must always outlive the tevent timer.
435 * The Python timer has a pointer to the tevent timer; a destructor is
436 * used to set this to NULL when the tevent timer is deallocated.
438 * The tevent timer can be deallocated in these cases:
439 * 1) when the context is destroyed
440 * 2) after the event fires
441 * Posssibly, API might be added to cancel (free the tevent timer).
443 * The Python timer holds a reference to the callback.
445 TeventTimer_Object
*ret
;
446 struct TeventTimer_Object_ref
*ref
;
448 ret
= PyObject_New(TeventTimer_Object
, &TeventTimer_Type
);
454 ret
->callback
= callback
;
455 ret
->timer
= tevent_add_timer(self
->ev
, NULL
, next_event
, py_timer_handler
,
457 if (ret
->timer
== NULL
) {
459 PyErr_SetString(PyExc_RuntimeError
, "Could not initialize timer");
462 ref
= talloc(ret
->timer
, struct TeventTimer_Object_ref
);
464 talloc_free(ret
->timer
);
466 PyErr_SetString(PyExc_RuntimeError
, "Could not initialize timer");
472 talloc_set_destructor(ref
, TeventTimer_Object_ref_destructor
);
474 return (PyObject
*)ret
;
477 static PyObject
*py_tevent_context_add_timer(TeventContext_Object
*self
, PyObject
*args
)
479 struct timeval next_event
;
481 if (!PyArg_ParseTuple(args
, "lO", &next_event
, &callback
))
484 return py_tevent_context_add_timer_internal(self
, next_event
, callback
);
487 static PyObject
*py_tevent_context_add_timer_offset(TeventContext_Object
*self
, PyObject
*args
)
489 struct timeval next_event
;
493 if (!PyArg_ParseTuple(args
, "dO", &offset
, &callback
))
498 next_event
= tevent_timeval_current_ofs(seconds
, (int)(offset
*1000000));
499 return py_tevent_context_add_timer_internal(self
, next_event
, callback
);
502 static void py_fd_handler(struct tevent_context
*ev
,
503 struct tevent_fd
*fde
,
507 PyObject
*callback
= private_data
, *ret
;
509 ret
= PyObject_CallFunction(callback
, discard_const_p(char, "i"), flags
);
513 static void py_tevent_fp_dealloc(TeventFd_Object
*self
)
515 talloc_free(self
->fd
);
519 static PyTypeObject TeventFd_Type
= {
520 .tp_name
= "tevent.Fd",
521 .tp_basicsize
= sizeof(TeventFd_Object
),
522 .tp_dealloc
= (destructor
)py_tevent_fp_dealloc
,
523 .tp_flags
= Py_TPFLAGS_DEFAULT
,
526 static PyObject
*py_tevent_context_add_fd(TeventContext_Object
*self
, PyObject
*args
)
530 struct tevent_fd
*tfd
;
531 TeventFd_Object
*ret
;
533 if (!PyArg_ParseTuple(args
, "iiO", &fd
, &flags
, &handler
))
536 tfd
= tevent_add_fd(self
->ev
, NULL
, fd
, flags
, py_fd_handler
, handler
);
538 PyErr_SetNone(PyExc_RuntimeError
);
542 ret
= PyObject_New(TeventFd_Object
, &TeventFd_Type
);
549 return (PyObject
*)ret
;
552 static PyMethodDef py_tevent_context_methods
[] = {
553 { "reinitialise", (PyCFunction
)py_tevent_context_reinitialise
, METH_NOARGS
,
554 "S.reinitialise()" },
555 { "wakeup_send", (PyCFunction
)py_tevent_context_wakeup_send
,
556 METH_VARARGS
, "S.wakeup_send(wakeup_time) -> req" },
557 { "loop_wait", (PyCFunction
)py_tevent_context_loop_wait
,
558 METH_NOARGS
, "S.loop_wait()" },
559 { "loop_once", (PyCFunction
)py_tevent_context_loop_once
,
560 METH_NOARGS
, "S.loop_once()" },
561 { "add_signal", (PyCFunction
)py_tevent_context_add_signal
,
562 METH_VARARGS
, "S.add_signal(signum, sa_flags, handler) -> signal" },
563 { "add_timer", (PyCFunction
)py_tevent_context_add_timer
,
564 METH_VARARGS
, "S.add_timer(next_event, handler) -> timer" },
565 { "add_timer_offset", (PyCFunction
)py_tevent_context_add_timer_offset
,
566 METH_VARARGS
, "S.add_timer(offset_seconds, handler) -> timer" },
567 { "add_fd", (PyCFunction
)py_tevent_context_add_fd
,
568 METH_VARARGS
, "S.add_fd(fd, flags, handler) -> fd" },
572 static PyObject
*py_tevent_req_wakeup_recv(PyObject
*self
)
578 static PyObject
*py_tevent_req_received(PyObject
*self
)
584 static PyObject
*py_tevent_req_is_error(PyObject
*self
)
590 static PyObject
*py_tevent_req_poll(PyObject
*self
)
596 static PyObject
*py_tevent_req_is_in_progress(PyObject
*self
)
602 static PyGetSetDef py_tevent_req_getsetters
[] = {
604 .name
= discard_const_p(char, "in_progress"),
605 .get
= (getter
)py_tevent_req_is_in_progress
,
606 .doc
= discard_const_p(char, "Whether the request is in progress"),
611 static PyObject
*py_tevent_req_post(PyObject
*self
, PyObject
*args
)
617 static PyObject
*py_tevent_req_set_error(PyObject
*self
, PyObject
*args
)
623 static PyObject
*py_tevent_req_done(PyObject
*self
)
629 static PyObject
*py_tevent_req_notify_callback(PyObject
*self
)
635 static PyObject
*py_tevent_req_set_endtime(PyObject
*self
, PyObject
*args
)
641 static PyObject
*py_tevent_req_cancel(TeventReq_Object
*self
)
643 if (!tevent_req_cancel(self
->req
)) {
644 PyErr_SetNone(PyExc_RuntimeError
);
650 static PyMethodDef py_tevent_req_methods
[] = {
651 { "wakeup_recv", (PyCFunction
)py_tevent_req_wakeup_recv
, METH_NOARGS
,
653 { "received", (PyCFunction
)py_tevent_req_received
, METH_NOARGS
,
654 "Receive finished" },
655 { "is_error", (PyCFunction
)py_tevent_req_is_error
, METH_NOARGS
,
656 "is_error() -> (error, state)" },
657 { "poll", (PyCFunction
)py_tevent_req_poll
, METH_VARARGS
,
659 { "post", (PyCFunction
)py_tevent_req_post
, METH_VARARGS
,
660 "post(ctx) -> req" },
661 { "set_error", (PyCFunction
)py_tevent_req_set_error
, METH_VARARGS
,
662 "set_error(error)" },
663 { "done", (PyCFunction
)py_tevent_req_done
, METH_NOARGS
,
665 { "notify_callback", (PyCFunction
)py_tevent_req_notify_callback
,
666 METH_NOARGS
, "notify_callback()" },
667 { "set_endtime", (PyCFunction
)py_tevent_req_set_endtime
,
668 METH_VARARGS
, "set_endtime(ctx, endtime)" },
669 { "cancel", (PyCFunction
)py_tevent_req_cancel
,
670 METH_NOARGS
, "cancel()" },
674 static void py_tevent_req_dealloc(TeventReq_Object
*self
)
676 talloc_free(self
->req
);
680 static PyTypeObject TeventReq_Type
= {
681 .tp_name
= "tevent.Request",
682 .tp_basicsize
= sizeof(TeventReq_Object
),
683 .tp_methods
= py_tevent_req_methods
,
684 .tp_dealloc
= (destructor
)py_tevent_req_dealloc
,
685 .tp_getset
= py_tevent_req_getsetters
,
686 /* FIXME: .tp_new = py_tevent_req_new, */
689 static PyObject
*py_tevent_queue_get_length(TeventQueue_Object
*self
)
691 return PyInt_FromLong(tevent_queue_length(self
->queue
));
694 static PyGetSetDef py_tevent_queue_getsetters
[] = {
696 .name
= discard_const_p(char, "length"),
697 .get
= (getter
)py_tevent_queue_get_length
,
698 .doc
= discard_const_p(char, "The number of elements in the queue."),
703 static void py_tevent_queue_dealloc(TeventQueue_Object
*self
)
705 talloc_free(self
->queue
);
709 static PyTypeObject TeventQueue_Type
= {
710 .tp_name
= "tevent.Queue",
711 .tp_basicsize
= sizeof(TeventQueue_Object
),
712 .tp_dealloc
= (destructor
)py_tevent_queue_dealloc
,
713 .tp_flags
= Py_TPFLAGS_DEFAULT
,
714 .tp_getset
= py_tevent_queue_getsetters
,
715 .tp_methods
= py_tevent_queue_methods
,
718 static PyObject
*py_tevent_context_signal_support(PyObject
*_self
)
720 TeventContext_Object
*self
= (TeventContext_Object
*)_self
;
721 return PyBool_FromLong(tevent_signal_support(self
->ev
));
724 static PyGetSetDef py_tevent_context_getsetters
[] = {
726 .name
= discard_const_p(char, "signal_support"),
727 .get
= (getter
)py_tevent_context_signal_support
,
728 .doc
= discard_const_p(char, "if this platform and tevent context support signal handling"),
733 static void py_tevent_context_dealloc(TeventContext_Object
*self
)
735 talloc_free(self
->ev
);
739 static PyObject
*py_tevent_context_new(PyTypeObject
*type
, PyObject
*args
, PyObject
*kwargs
)
741 const char * const kwnames
[] = { "name", NULL
};
743 struct tevent_context
*ev
;
744 TeventContext_Object
*ret
;
746 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "|s", discard_const_p(char *, kwnames
), &name
))
750 ev
= tevent_context_init(NULL
);
752 ev
= tevent_context_init_byname(NULL
, name
);
756 PyErr_SetNone(PyExc_RuntimeError
);
760 ret
= PyObject_New(TeventContext_Object
, type
);
768 return (PyObject
*)ret
;
771 static PyTypeObject TeventContext_Type
= {
772 .tp_name
= "tevent.Context",
773 .tp_new
= py_tevent_context_new
,
774 .tp_basicsize
= sizeof(TeventContext_Object
),
775 .tp_dealloc
= (destructor
)py_tevent_context_dealloc
,
776 .tp_methods
= py_tevent_context_methods
,
777 .tp_getset
= py_tevent_context_getsetters
,
778 .tp_flags
= Py_TPFLAGS_DEFAULT
,
781 static PyObject
*py_set_default_backend(PyObject
*self
, PyObject
*args
)
784 if (!PyArg_ParseTuple(args
, "s", &backend_name
))
787 tevent_set_default_backend(backend_name
);
792 static PyObject
*py_backend_list(PyObject
*self
)
794 PyObject
*ret
= NULL
;
795 PyObject
*string
= NULL
;
797 const char **backends
= NULL
;
804 backends
= tevent_backend_list(NULL
);
805 if (backends
== NULL
) {
806 PyErr_SetNone(PyExc_RuntimeError
);
809 for (i
= 0; backends
[i
]; i
++) {
810 string
= PyStr_FromString(backends
[i
]);
814 result
= PyList_Append(ret
, string
);
822 talloc_free(backends
);
829 talloc_free(backends
);
833 static PyMethodDef tevent_methods
[] = {
834 { "register_backend", (PyCFunction
)py_register_backend
, METH_VARARGS
,
835 "register_backend(backend)" },
836 { "set_default_backend", (PyCFunction
)py_set_default_backend
,
837 METH_VARARGS
, "set_default_backend(backend)" },
838 { "backend_list", (PyCFunction
)py_backend_list
,
839 METH_NOARGS
, "backend_list() -> list" },
843 #define MODULE_DOC PyDoc_STR("Python wrapping of talloc-maintained objects.")
845 #if PY_MAJOR_VERSION >= 3
846 static struct PyModuleDef moduledef
= {
847 PyModuleDef_HEAD_INIT
,
851 .m_methods
= tevent_methods
,
855 PyObject
* module_init(void);
856 PyObject
* module_init(void)
860 if (PyType_Ready(&TeventContext_Type
) < 0)
863 if (PyType_Ready(&TeventQueue_Type
) < 0)
866 if (PyType_Ready(&TeventReq_Type
) < 0)
869 if (PyType_Ready(&TeventSignal_Type
) < 0)
872 if (PyType_Ready(&TeventTimer_Type
) < 0)
875 if (PyType_Ready(&TeventFd_Type
) < 0)
878 #if PY_MAJOR_VERSION >= 3
879 m
= PyModule_Create(&moduledef
);
881 m
= Py_InitModule3("_tevent", tevent_methods
, MODULE_DOC
);
886 Py_INCREF(&TeventContext_Type
);
887 PyModule_AddObject(m
, "Context", (PyObject
*)&TeventContext_Type
);
889 Py_INCREF(&TeventQueue_Type
);
890 PyModule_AddObject(m
, "Queue", (PyObject
*)&TeventQueue_Type
);
892 Py_INCREF(&TeventReq_Type
);
893 PyModule_AddObject(m
, "Request", (PyObject
*)&TeventReq_Type
);
895 Py_INCREF(&TeventSignal_Type
);
896 PyModule_AddObject(m
, "Signal", (PyObject
*)&TeventSignal_Type
);
898 Py_INCREF(&TeventTimer_Type
);
899 PyModule_AddObject(m
, "Timer", (PyObject
*)&TeventTimer_Type
);
901 Py_INCREF(&TeventFd_Type
);
902 PyModule_AddObject(m
, "Fd", (PyObject
*)&TeventFd_Type
);
904 PyModule_AddStringConstant(m
, "__version__", PACKAGE_VERSION
);
909 #if PY_MAJOR_VERSION >= 3
910 PyMODINIT_FUNC
PyInit__tevent(void);
911 PyMODINIT_FUNC
PyInit__tevent(void)
913 return module_init();
916 void init_tevent(void);
917 void init_tevent(void)