source: trunk/server/lib/tevent/pytevent.c@ 812

Last change on this file since 812 was 745, checked in by Silvan Scherrer, 13 years ago

Samba Server: updated trunk to 3.6.0

File size: 18.6 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3 Python bindings for tevent
4
5 Copyright (C) Jelmer Vernooij 2010
6
7 ** NOTE! The following LGPL license applies to the tevent
8 ** library. This does NOT imply that all of Samba is released
9 ** under the LGPL
10
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.
15
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.
20
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/>.
23*/
24
25#include <Python.h>
26#include <tevent.h>
27
28typedef struct {
29 PyObject_HEAD
30 struct tevent_context *ev;
31} TeventContext_Object;
32
33typedef struct {
34 PyObject_HEAD
35 struct tevent_queue *queue;
36} TeventQueue_Object;
37
38typedef struct {
39 PyObject_HEAD
40 struct tevent_req *req;
41} TeventReq_Object;
42
43typedef struct {
44 PyObject_HEAD
45 struct tevent_signal *signal;
46} TeventSignal_Object;
47
48typedef struct {
49 PyObject_HEAD
50 struct tevent_timer *timer;
51} TeventTimer_Object;
52
53typedef struct {
54 PyObject_HEAD
55 struct tevent_fd *fd;
56} TeventFd_Object;
57
58staticforward PyTypeObject TeventContext_Type;
59staticforward PyTypeObject TeventReq_Type;
60staticforward PyTypeObject TeventQueue_Type;
61staticforward PyTypeObject TeventSignal_Type;
62staticforward PyTypeObject TeventTimer_Type;
63staticforward PyTypeObject TeventFd_Type;
64
65static int py_context_init(struct tevent_context *ev)
66{
67 /* FIXME */
68 return 0;
69}
70
71static struct tevent_fd *py_add_fd(struct tevent_context *ev,
72 TALLOC_CTX *mem_ctx,
73 int fd, uint16_t flags,
74 tevent_fd_handler_t handler,
75 void *private_data,
76 const char *handler_name,
77 const char *location)
78{
79 /* FIXME */
80 return NULL;
81}
82
83static void py_set_fd_close_fn(struct tevent_fd *fde,
84 tevent_fd_close_fn_t close_fn)
85{
86 /* FIXME */
87}
88
89uint16_t py_get_fd_flags(struct tevent_fd *fde)
90{
91 /* FIXME */
92 return 0;
93}
94
95static void py_set_fd_flags(struct tevent_fd *fde, uint16_t flags)
96{
97 /* FIXME */
98}
99
100/* timed_event functions */
101static struct tevent_timer *py_add_timer(struct tevent_context *ev,
102 TALLOC_CTX *mem_ctx,
103 struct timeval next_event,
104 tevent_timer_handler_t handler,
105 void *private_data,
106 const char *handler_name,
107 const char *location)
108{
109 /* FIXME */
110 return NULL;
111}
112
113/* immediate event functions */
114static void py_schedule_immediate(struct tevent_immediate *im,
115 struct tevent_context *ev,
116 tevent_immediate_handler_t handler,
117 void *private_data,
118 const char *handler_name,
119 const char *location)
120{
121 /* FIXME */
122}
123
124/* signal functions */
125static struct tevent_signal *py_add_signal(struct tevent_context *ev,
126 TALLOC_CTX *mem_ctx,
127 int signum, int sa_flags,
128 tevent_signal_handler_t handler,
129 void *private_data,
130 const char *handler_name,
131 const char *location)
132{
133 /* FIXME */
134 return NULL;
135}
136
137/* loop functions */
138static int py_loop_once(struct tevent_context *ev, const char *location)
139{
140 /* FIXME */
141 return 0;
142}
143
144static int py_loop_wait(struct tevent_context *ev, const char *location)
145{
146 /* FIXME */
147 return 0;
148}
149
150const static struct tevent_ops py_tevent_ops = {
151 .context_init = py_context_init,
152 .add_fd = py_add_fd,
153 .set_fd_close_fn = py_set_fd_close_fn,
154 .get_fd_flags = py_get_fd_flags,
155 .set_fd_flags = py_set_fd_flags,
156 .add_timer = py_add_timer,
157 .schedule_immediate = py_schedule_immediate,
158 .add_signal = py_add_signal,
159 .loop_wait = py_loop_wait,
160 .loop_once = py_loop_once,
161};
162
163static PyObject *py_register_backend(PyObject *self, PyObject *args)
164{
165 PyObject *name, *py_backend;
166
167 if (!PyArg_ParseTuple(args, "O", &py_backend))
168 return NULL;
169
170 name = PyObject_GetAttrString(py_backend, "name");
171 if (name == NULL) {
172 PyErr_SetNone(PyExc_AttributeError);
173 return NULL;
174 }
175
176 if (!PyString_Check(name)) {
177 PyErr_SetNone(PyExc_TypeError);
178 return NULL;
179 }
180
181 if (!tevent_register_backend(PyString_AsString(name), &py_tevent_ops)) { /* FIXME: What to do with backend */
182 PyErr_SetNone(PyExc_RuntimeError);
183 return NULL;
184 }
185
186 Py_RETURN_NONE;
187}
188
189static PyObject *py_tevent_context_reinitialise(TeventContext_Object *self)
190{
191 int ret = tevent_re_initialise(self->ev);
192 if (ret != 0) {
193 PyErr_SetNone(PyExc_RuntimeError);
194 return NULL;
195 }
196 Py_RETURN_NONE;
197}
198
199static PyObject *py_tevent_queue_stop(TeventQueue_Object *self)
200{
201 tevent_queue_stop(self->queue);
202 Py_RETURN_NONE;
203}
204
205static PyObject *py_tevent_queue_start(TeventQueue_Object *self)
206{
207 tevent_queue_start(self->queue);
208 Py_RETURN_NONE;
209}
210
211static void py_queue_trigger(struct tevent_req *req, void *private_data)
212{
213 PyObject *callback = private_data, *ret;
214
215 ret = PyObject_CallFunction(callback, "");
216 Py_XDECREF(ret);
217}
218
219static PyObject *py_tevent_queue_add(TeventQueue_Object *self, PyObject *args)
220{
221 TeventContext_Object *py_ev;
222 TeventReq_Object *py_req;
223 PyObject *trigger;
224 bool ret;
225
226 if (!PyArg_ParseTuple(args, "O!O!O",
227 &TeventContext_Type, &py_ev,
228 &TeventReq_Type, &py_req,
229 &trigger))
230 return NULL;
231
232 Py_INCREF(trigger);
233
234 ret = tevent_queue_add(self->queue, py_ev->ev, py_req->req,
235 py_queue_trigger, trigger);
236 if (!ret) {
237 PyErr_SetString(PyExc_RuntimeError, "queue add failed");
238 Py_DECREF(trigger);
239 return NULL;
240 }
241
242 Py_RETURN_NONE;
243}
244
245static PyMethodDef py_tevent_queue_methods[] = {
246 { "stop", (PyCFunction)py_tevent_queue_stop, METH_NOARGS,
247 "S.stop()" },
248 { "start", (PyCFunction)py_tevent_queue_start, METH_NOARGS,
249 "S.start()" },
250 { "add", (PyCFunction)py_tevent_queue_add, METH_VARARGS,
251 "S.add(ctx, req, trigger, baton)" },
252 { NULL },
253};
254
255static PyObject *py_tevent_context_wakeup_send(PyObject *self, PyObject *args)
256{
257 /* FIXME */
258
259 Py_RETURN_NONE;
260}
261
262static PyObject *py_tevent_context_loop_wait(TeventContext_Object *self)
263{
264 if (tevent_loop_wait(self->ev) != 0) {
265 PyErr_SetNone(PyExc_RuntimeError);
266 return NULL;
267 }
268 Py_RETURN_NONE;
269}
270
271static PyObject *py_tevent_context_loop_once(TeventContext_Object *self)
272{
273 if (tevent_loop_once(self->ev) != 0) {
274 PyErr_SetNone(PyExc_RuntimeError);
275 return NULL;
276 }
277 Py_RETURN_NONE;
278}
279
280#ifdef TEVENT_DEPRECATED
281static bool py_tevent_finished(PyObject *callback)
282{
283 PyObject *py_ret;
284 bool ret;
285
286 py_ret = PyObject_CallFunction(callback, "");
287 if (py_ret == NULL)
288 return true;
289 ret = PyObject_IsTrue(py_ret);
290 Py_DECREF(py_ret);
291 return ret;
292}
293
294static PyObject *py_tevent_context_loop_until(TeventContext_Object *self, PyObject *args)
295{
296 PyObject *callback;
297 if (!PyArg_ParseTuple(args, "O", &callback))
298 return NULL;
299
300 if (tevent_loop_until(self->ev, py_tevent_finished, callback) != 0) {
301 PyErr_SetNone(PyExc_RuntimeError);
302 return NULL;
303 }
304
305 if (PyErr_Occurred())
306 return NULL;
307
308 Py_RETURN_NONE;
309}
310#endif
311
312static void py_tevent_signal_handler(struct tevent_context *ev,
313 struct tevent_signal *se,
314 int signum,
315 int count,
316 void *siginfo,
317 void *private_data)
318{
319 PyObject *callback = (PyObject *)private_data, *ret;
320
321 ret = PyObject_CallFunction(callback, "ii", signum, count);
322 Py_XDECREF(ret);
323}
324
325static void py_tevent_signal_dealloc(TeventSignal_Object *self)
326{
327 talloc_free(self->signal);
328 PyObject_Del(self);
329}
330
331static PyTypeObject TeventSignal_Type = {
332 .tp_name = "Signal",
333 .tp_basicsize = sizeof(TeventSignal_Object),
334 .tp_dealloc = (destructor)py_tevent_signal_dealloc,
335 .tp_flags = Py_TPFLAGS_DEFAULT,
336};
337
338static PyObject *py_tevent_context_add_signal(TeventContext_Object *self, PyObject *args)
339{
340 int signum, sa_flags;
341 PyObject *handler;
342 struct tevent_signal *sig;
343 TeventSignal_Object *ret;
344
345 if (!PyArg_ParseTuple(args, "iiO", &signum, &sa_flags, &handler))
346 return NULL;
347
348 Py_INCREF(handler);
349 sig = tevent_add_signal(self->ev, NULL, signum, sa_flags,
350 py_tevent_signal_handler, handler);
351
352 ret = PyObject_New(TeventSignal_Object, &TeventSignal_Type);
353 if (ret == NULL) {
354 PyErr_NoMemory();
355 talloc_free(sig);
356 return NULL;
357 }
358
359 ret->signal = sig;
360
361 return (PyObject *)ret;
362}
363
364static void py_timer_handler(struct tevent_context *ev,
365 struct tevent_timer *te,
366 struct timeval current_time,
367 void *private_data)
368{
369 PyObject *callback = private_data, *ret;
370 ret = PyObject_CallFunction(callback, "l", te);
371 Py_XDECREF(ret);
372}
373
374static PyObject *py_tevent_context_add_timer(TeventContext_Object *self, PyObject *args)
375{
376 TeventTimer_Object *ret;
377 struct timeval next_event;
378 struct tevent_timer *timer;
379 PyObject *handler;
380 if (!PyArg_ParseTuple(args, "lO", &next_event, &handler))
381 return NULL;
382
383 timer = tevent_add_timer(self->ev, NULL, next_event, py_timer_handler,
384 handler);
385 if (timer == NULL) {
386 PyErr_SetNone(PyExc_RuntimeError);
387 return NULL;
388 }
389
390 ret = PyObject_New(TeventTimer_Object, &TeventTimer_Type);
391 if (ret == NULL) {
392 PyErr_NoMemory();
393 talloc_free(timer);
394 return NULL;
395 }
396 ret->timer = timer;
397
398 return (PyObject *)ret;
399}
400
401static void py_fd_handler(struct tevent_context *ev,
402 struct tevent_fd *fde,
403 uint16_t flags,
404 void *private_data)
405{
406 PyObject *callback = private_data, *ret;
407
408 ret = PyObject_CallFunction(callback, "i", flags);
409 Py_XDECREF(ret);
410}
411
412static PyObject *py_tevent_context_add_fd(TeventContext_Object *self, PyObject *args)
413{
414 int fd, flags;
415 PyObject *handler;
416 struct tevent_fd *tfd;
417 TeventFd_Object *ret;
418
419 if (!PyArg_ParseTuple(args, "iiO", &fd, &flags, &handler))
420 return NULL;
421
422 tfd = tevent_add_fd(self->ev, NULL, fd, flags, py_fd_handler, handler);
423 if (tfd == NULL) {
424 PyErr_SetNone(PyExc_RuntimeError);
425 return NULL;
426 }
427
428 ret = PyObject_New(TeventFd_Object, &TeventFd_Type);
429 if (ret == NULL) {
430 talloc_free(tfd);
431 return NULL;
432 }
433 ret->fd = tfd;
434
435 return (PyObject *)ret;
436}
437
438#ifdef TEVENT_DEPRECATED
439static PyObject *py_tevent_context_set_allow_nesting(TeventContext_Object *self)
440{
441 tevent_loop_allow_nesting(self->ev);
442 Py_RETURN_NONE;
443}
444#endif
445
446static PyMethodDef py_tevent_context_methods[] = {
447 { "reinitialise", (PyCFunction)py_tevent_context_reinitialise, METH_NOARGS,
448 "S.reinitialise()" },
449 { "wakeup_send", (PyCFunction)py_tevent_context_wakeup_send,
450 METH_VARARGS, "S.wakeup_send(wakeup_time) -> req" },
451 { "loop_wait", (PyCFunction)py_tevent_context_loop_wait,
452 METH_NOARGS, "S.loop_wait()" },
453 { "loop_once", (PyCFunction)py_tevent_context_loop_once,
454 METH_NOARGS, "S.loop_once()" },
455#ifdef TEVENT_DEPRECATED
456 { "loop_until", (PyCFunction)py_tevent_context_loop_until,
457 METH_VARARGS, "S.loop_until(callback)" },
458#endif
459 { "add_signal", (PyCFunction)py_tevent_context_add_signal,
460 METH_VARARGS, "S.add_signal(signum, sa_flags, handler) -> signal" },
461 { "add_timer", (PyCFunction)py_tevent_context_add_timer,
462 METH_VARARGS, "S.add_timer(next_event, handler) -> timer" },
463 { "add_fd", (PyCFunction)py_tevent_context_add_fd,
464 METH_VARARGS, "S.add_fd(fd, flags, handler) -> fd" },
465#ifdef TEVENT_DEPRECATED
466 { "allow_nesting", (PyCFunction)py_tevent_context_set_allow_nesting,
467 METH_NOARGS, "Whether to allow nested tevent loops." },
468#endif
469 { NULL },
470};
471
472static PyObject *py_tevent_req_wakeup_recv(PyObject *self)
473{
474 /* FIXME */
475 Py_RETURN_NONE;
476}
477
478static PyObject *py_tevent_req_received(PyObject *self)
479{
480 /* FIXME */
481 Py_RETURN_NONE;
482}
483
484static PyObject *py_tevent_req_is_error(PyObject *self)
485{
486 /* FIXME */
487 Py_RETURN_NONE;
488}
489
490static PyObject *py_tevent_req_poll(PyObject *self)
491{
492 /* FIXME */
493 Py_RETURN_NONE;
494}
495
496static PyObject *py_tevent_req_is_in_progress(PyObject *self)
497{
498 /* FIXME */
499 Py_RETURN_NONE;
500}
501
502static PyGetSetDef py_tevent_req_getsetters[] = {
503 { "in_progress", (getter)py_tevent_req_is_in_progress, NULL,
504 "Whether the request is in progress" },
505 { NULL }
506};
507
508static PyObject *py_tevent_req_post(PyObject *self, PyObject *args)
509{
510 /* FIXME */
511 Py_RETURN_NONE;
512}
513
514static PyObject *py_tevent_req_set_error(PyObject *self, PyObject *args)
515{
516 /* FIXME */
517 Py_RETURN_NONE;
518}
519
520static PyObject *py_tevent_req_done(PyObject *self)
521{
522 /* FIXME */
523 Py_RETURN_NONE;
524}
525
526static PyObject *py_tevent_req_notify_callback(PyObject *self)
527{
528 /* FIXME */
529 Py_RETURN_NONE;
530}
531
532static PyObject *py_tevent_req_set_endtime(PyObject *self, PyObject *args)
533{
534 /* FIXME */
535 Py_RETURN_NONE;
536}
537
538static PyObject *py_tevent_req_cancel(TeventReq_Object *self)
539{
540 if (!tevent_req_cancel(self->req)) {
541 PyErr_SetNone(PyExc_RuntimeError);
542 return NULL;
543 }
544 Py_RETURN_NONE;
545}
546
547static PyMethodDef py_tevent_req_methods[] = {
548 { "wakeup_recv", (PyCFunction)py_tevent_req_wakeup_recv, METH_NOARGS,
549 "Wakeup received" },
550 { "received", (PyCFunction)py_tevent_req_received, METH_NOARGS,
551 "Receive finished" },
552 { "is_error", (PyCFunction)py_tevent_req_is_error, METH_NOARGS,
553 "is_error() -> (error, state)" },
554 { "poll", (PyCFunction)py_tevent_req_poll, METH_VARARGS,
555 "poll(ctx)" },
556 { "post", (PyCFunction)py_tevent_req_post, METH_VARARGS,
557 "post(ctx) -> req" },
558 { "set_error", (PyCFunction)py_tevent_req_set_error, METH_VARARGS,
559 "set_error(error)" },
560 { "done", (PyCFunction)py_tevent_req_done, METH_NOARGS,
561 "done()" },
562 { "notify_callback", (PyCFunction)py_tevent_req_notify_callback,
563 METH_NOARGS, "notify_callback()" },
564 { "set_endtime", (PyCFunction)py_tevent_req_set_endtime,
565 METH_VARARGS, "set_endtime(ctx, endtime)" },
566 { "cancel", (PyCFunction)py_tevent_req_cancel,
567 METH_NOARGS, "cancel()" },
568 { NULL }
569};
570
571static void py_tevent_req_dealloc(TeventReq_Object *self)
572{
573 talloc_free(self->req);
574 PyObject_DEL(self);
575}
576
577static PyTypeObject TeventReq_Type = {
578 .tp_name = "tevent.Request",
579 .tp_basicsize = sizeof(TeventReq_Object),
580 .tp_methods = py_tevent_req_methods,
581 .tp_dealloc = (destructor)py_tevent_req_dealloc,
582 .tp_getset = py_tevent_req_getsetters,
583 /* FIXME: .tp_new = py_tevent_req_new, */
584};
585
586static PyObject *py_tevent_queue_get_length(TeventQueue_Object *self)
587{
588 return PyInt_FromLong(tevent_queue_length(self->queue));
589}
590
591static PyGetSetDef py_tevent_queue_getsetters[] = {
592 { "length", (getter)py_tevent_queue_get_length,
593 NULL, "The number of elements in the queue." },
594 { NULL },
595};
596
597static void py_tevent_queue_dealloc(TeventQueue_Object *self)
598{
599 talloc_free(self->queue);
600 PyObject_Del(self);
601}
602
603static PyTypeObject TeventQueue_Type = {
604 .tp_name = "tevent.Queue",
605 .tp_basicsize = sizeof(TeventQueue_Object),
606 .tp_dealloc = (destructor)py_tevent_queue_dealloc,
607 .tp_flags = Py_TPFLAGS_DEFAULT,
608 .tp_getset = py_tevent_queue_getsetters,
609 .tp_methods = py_tevent_queue_methods,
610};
611
612static PyObject *py_tevent_context_signal_support(PyObject *_self)
613{
614 TeventContext_Object *self = (TeventContext_Object *)_self;
615 return PyBool_FromLong(tevent_signal_support(self->ev));
616}
617
618static PyGetSetDef py_tevent_context_getsetters[] = {
619 { "signal_support", (getter)py_tevent_context_signal_support,
620 NULL, "if this platform and tevent context support signal handling" },
621 { NULL }
622};
623
624static void py_tevent_context_dealloc(TeventContext_Object *self)
625{
626 talloc_free(self->ev);
627 PyObject_Del(self);
628}
629
630static PyObject *py_tevent_context_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
631{
632 const char * const kwnames[] = { "name", NULL };
633 char *name = NULL;
634 struct tevent_context *ev;
635 TeventContext_Object *ret;
636
637 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|s", kwnames, &name))
638 return NULL;
639
640 if (name == NULL) {
641 ev = tevent_context_init(NULL);
642 } else {
643 ev = tevent_context_init_byname(NULL, name);
644 }
645
646 if (ev == NULL) {
647 PyErr_SetNone(PyExc_RuntimeError);
648 return NULL;
649 }
650
651 ret = PyObject_New(TeventContext_Object, type);
652 if (ret == NULL) {
653 PyErr_NoMemory();
654 talloc_free(ev);
655 return NULL;
656 }
657
658 ret->ev = ev;
659 return (PyObject *)ret;
660}
661
662static PyTypeObject TeventContext_Type = {
663 .tp_name = "_tevent.Context",
664 .tp_new = py_tevent_context_new,
665 .tp_basicsize = sizeof(TeventContext_Object),
666 .tp_dealloc = (destructor)py_tevent_context_dealloc,
667 .tp_methods = py_tevent_context_methods,
668 .tp_getset = py_tevent_context_getsetters,
669 .tp_flags = Py_TPFLAGS_DEFAULT,
670};
671
672static PyObject *py_set_default_backend(PyObject *self, PyObject *args)
673{
674 char *backend_name;
675 if (!PyArg_ParseTuple(args, "s", &backend_name))
676 return NULL;
677
678 tevent_set_default_backend(backend_name);
679
680 Py_RETURN_NONE;
681}
682
683static PyObject *py_backend_list(PyObject *self)
684{
685 PyObject *ret;
686 int i;
687 const char **backends;
688
689 ret = PyList_New(0);
690 if (ret == NULL) {
691 return NULL;
692 }
693
694 backends = tevent_backend_list(NULL);
695 if (backends == NULL) {
696 PyErr_SetNone(PyExc_RuntimeError);
697 Py_DECREF(ret);
698 return NULL;
699 }
700 for (i = 0; backends[i]; i++) {
701 PyList_Append(ret, PyString_FromString(backends[i]));
702 }
703
704 talloc_free(backends);
705
706 return ret;
707}
708
709static PyMethodDef tevent_methods[] = {
710 { "register_backend", (PyCFunction)py_register_backend, METH_VARARGS,
711 "register_backend(backend)" },
712 { "set_default_backend", (PyCFunction)py_set_default_backend,
713 METH_VARARGS, "set_default_backend(backend)" },
714 { "backend_list", (PyCFunction)py_backend_list,
715 METH_NOARGS, "backend_list() -> list" },
716 { NULL },
717};
718
719void init_tevent(void)
720{
721 PyObject *m;
722
723 if (PyType_Ready(&TeventContext_Type) < 0)
724 return;
725
726 if (PyType_Ready(&TeventQueue_Type) < 0)
727 return;
728
729 if (PyType_Ready(&TeventReq_Type) < 0)
730 return;
731
732 if (PyType_Ready(&TeventSignal_Type) < 0)
733 return;
734
735 if (PyType_Ready(&TeventTimer_Type) < 0)
736 return;
737
738 if (PyType_Ready(&TeventFd_Type) < 0)
739 return;
740
741 m = Py_InitModule3("_tevent", tevent_methods, "Tevent integration for twisted.");
742 if (m == NULL)
743 return;
744
745 Py_INCREF(&TeventContext_Type);
746 PyModule_AddObject(m, "Context", (PyObject *)&TeventContext_Type);
747
748 Py_INCREF(&TeventQueue_Type);
749 PyModule_AddObject(m, "Queue", (PyObject *)&TeventQueue_Type);
750
751 Py_INCREF(&TeventReq_Type);
752 PyModule_AddObject(m, "Request", (PyObject *)&TeventReq_Type);
753
754 Py_INCREF(&TeventSignal_Type);
755 PyModule_AddObject(m, "Signal", (PyObject *)&TeventSignal_Type);
756
757 Py_INCREF(&TeventTimer_Type);
758 PyModule_AddObject(m, "Timer", (PyObject *)&TeventTimer_Type);
759
760 Py_INCREF(&TeventFd_Type);
761 PyModule_AddObject(m, "Fd", (PyObject *)&TeventFd_Type);
762}
Note: See TracBrowser for help on using the repository browser.