a66d1958e9806c85bf087747ce8b3d29e254e4fb
[vuplus_dvbapp] / lib / base / ebase.cpp
1 #include <lib/base/ebase.h>
2
3 #include <fcntl.h>
4 #include <unistd.h>
5 #include <errno.h>
6
7 #include <lib/base/eerror.h>
8 #include <lib/base/elock.h>
9 #include <lib/gdi/grc.h>
10
11 DEFINE_REF(eSocketNotifier);
12
13 eSocketNotifier::eSocketNotifier(eMainloop *context, int fd, int requested, bool startnow): context(*context), fd(fd), state(0), requested(requested)
14 {
15         if (startnow)
16                 start();
17 }
18
19 eSocketNotifier::~eSocketNotifier()
20 {
21         stop();
22 }
23
24 void eSocketNotifier::start()
25 {
26         if (state)
27                 stop();
28
29         context.addSocketNotifier(this);
30         state=2;  // running but not in poll yet
31 }
32
33 void eSocketNotifier::stop()
34 {
35         if (state)
36         {
37                 state=0;
38                 context.removeSocketNotifier(this);
39         }
40 }
41
42                                         // timer
43 void eTimer::start(long msek, bool singleShot)
44 {
45         if (bActive)
46                 stop();
47
48         bActive = true;
49         bSingleShot = singleShot;
50         interval = msek;
51         clock_gettime(CLOCK_MONOTONIC, &nextActivation);
52 //      eDebug("this = %p\nnow sec = %d, nsec = %d\nadd %d msec", this, nextActivation.tv_sec, nextActivation.tv_nsec, msek);
53         nextActivation += (msek<0 ? 0 : msek);
54 //      eDebug("next Activation sec = %d, nsec = %d", nextActivation.tv_sec, nextActivation.tv_nsec );
55         context.addTimer(this);
56 }
57
58 void eTimer::startLongTimer( int seconds )
59 {
60         if (bActive)
61                 stop();
62
63         bActive = bSingleShot = true;
64         interval = 0;
65         clock_gettime(CLOCK_MONOTONIC, &nextActivation);
66 //      eDebug("this = %p\nnow sec = %d, nsec = %d\nadd %d sec", this, nextActivation.tv_sec, nextActivation.tv_nsec, seconds);
67         if ( seconds > 0 )
68                 nextActivation.tv_sec += seconds;
69 //      eDebug("next Activation sec = %d, nsec = %d", nextActivation.tv_sec, nextActivation.tv_nsec );
70         context.addTimer(this);
71 }
72
73 void eTimer::stop()
74 {
75         if (bActive)
76         {
77                 bActive=false;
78                 context.removeTimer(this);
79         }
80 }
81
82 void eTimer::changeInterval(long msek)
83 {
84         if (bActive)  // Timer is running?
85         {
86                 context.removeTimer(this);       // then stop
87                 nextActivation -= interval;  // sub old interval
88         }
89         else
90                 bActive=true; // then activate Timer
91
92         interval = msek;                                                // set new Interval
93         nextActivation += interval;             // calc nextActivation
94
95         context.addTimer(this);                         // add Timer to context TimerList
96 }
97
98 void eTimer::activate()   // Internal Funktion... called from eApplication
99 {
100         context.removeTimer(this);
101
102         if (!bSingleShot)
103         {
104                 nextActivation += interval;
105                 context.addTimer(this);
106         }
107         else
108                 bActive=false;
109
110         /*emit*/ timeout();
111 }
112
113 // mainloop
114 ePtrList<eMainloop> eMainloop::existing_loops;
115
116 eMainloop::~eMainloop()
117 {
118         existing_loops.remove(this);
119         for (std::map<int, eSocketNotifier*>::iterator it(notifiers.begin());it != notifiers.end();++it)
120                 it->second->stop();
121         while(m_timer_list.begin() != m_timer_list.end())
122                 m_timer_list.begin()->stop();
123 }
124
125 void eMainloop::addSocketNotifier(eSocketNotifier *sn)
126 {
127         int fd = sn->getFD();
128         ASSERT(notifiers.find(fd) == notifiers.end());
129         notifiers[fd]=sn;
130 }
131
132 void eMainloop::removeSocketNotifier(eSocketNotifier *sn)
133 {
134         int fd = sn->getFD();
135         std::map<int,eSocketNotifier*>::iterator i(notifiers.find(fd));
136         if (i != notifiers.end())
137         {
138                 notifiers.erase(i);
139                 return;
140         }
141         for (i = notifiers.begin(); i != notifiers.end(); ++i)
142                 eDebug("fd=%d, sn=%d", i->second->getFD(), (void*)i->second);
143         eFatal("removed socket notifier which is not present, fd=%d", fd);
144 }
145
146 int eMainloop::processOneEvent(unsigned int twisted_timeout, PyObject **res, ePyObject additional)
147 {
148         int return_reason = 0;
149                 /* get current time */
150
151         if (additional && !PyDict_Check(additional))
152                 eFatal("additional, but it's not dict");
153
154         if (additional && !res)
155                 eFatal("additional, but no res");
156
157         long poll_timeout = -1; /* infinite in case of empty timer list */
158
159         if (!m_timer_list.empty())
160         {
161                 /* process all timers which are ready. first remove them out of the list. */
162                 while (!m_timer_list.empty() && (poll_timeout = timeout_usec( m_timer_list.begin()->getNextActivation() ) ) <= 0 )
163                         m_timer_list.begin()->activate();
164                 if (poll_timeout < 0)
165                         poll_timeout = 0;
166                 else /* convert us to ms */
167                         poll_timeout /= 1000;
168         }
169
170         if ((twisted_timeout > 0) && (poll_timeout > 0) && ((unsigned int)poll_timeout > twisted_timeout))
171         {
172                 poll_timeout = twisted_timeout;
173                 return_reason = 1;
174         }
175
176         int nativecount=notifiers.size(),
177                 fdcount=nativecount,
178                 ret=0;
179
180         if (additional)
181                 fdcount += PyDict_Size(additional);
182
183                 // build the poll aray
184         pollfd pfd[fdcount];  // make new pollfd array
185         std::map<int,eSocketNotifier*>::iterator it = notifiers.begin();
186
187         int i=0;
188         for (; i < nativecount; ++i, ++it)
189         {
190                 it->second->state = 1; // running and in poll
191                 pfd[i].fd = it->first;
192                 pfd[i].events = it->second->getRequested();
193         }
194
195         if (additional)
196         {
197 #if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN)
198                 typedef int Py_ssize_t;
199 # define PY_SSIZE_T_MAX INT_MAX
200 # define PY_SSIZE_T_MIN INT_MIN
201 #endif
202                 PyObject *key, *val;
203                 Py_ssize_t pos=0;
204                 while (PyDict_Next(additional, &pos, &key, &val)) {
205                         pfd[i].fd = PyObject_AsFileDescriptor(key);
206                         pfd[i++].events = PyInt_AsLong(val);
207                 }
208         }
209
210         m_is_idle = 1;
211
212         if (this == eApp)
213         {
214                 gOpcode op;
215                 op.dc = 0;
216                 op.opcode = gOpcode::flush;
217                 gRC::getInstance()->submit(op);
218                 Py_BEGIN_ALLOW_THREADS
219                 ret = ::poll(pfd, fdcount, poll_timeout);
220                 Py_END_ALLOW_THREADS
221                 
222         } else
223                 ret = ::poll(pfd, fdcount, poll_timeout);
224
225         m_is_idle = 0;
226
227                         /* ret > 0 means that there are some active poll entries. */
228         if (ret > 0)
229         {
230                 int i=0;
231                 return_reason = 0;
232                 for (; i < nativecount; ++i)
233                 {
234                         if (pfd[i].revents)
235                         {
236                                 it = notifiers.find(pfd[i].fd);
237                                 if (it != notifiers.end()
238                                         && it->second->state == 1) // added and in poll
239                                 {
240                                         eSocketNotifier *sn = it->second;
241                                         int req = sn->getRequested();
242                                         if (pfd[i].revents & req) {
243                                                 sn->AddRef();
244                                                 sn->activate(pfd[i].revents & req);
245                                                 sn->Release();
246                                         }
247                                         pfd[i].revents &= ~req;
248                                 }
249                                 if (pfd[i].revents & (POLLERR|POLLHUP|POLLNVAL))
250                                         eDebug("poll: unhandled POLLERR/HUP/NVAL for fd %d(%d)", pfd[i].fd, pfd[i].revents);
251                         }
252                 }
253                 for (; i < fdcount; ++i)
254                 {
255                         if (pfd[i].revents)
256                         {
257                                 if (!*res)
258                                         *res = PyList_New(0);
259                                 ePyObject it = PyTuple_New(2);
260                                 PyTuple_SET_ITEM(it, 0, PyInt_FromLong(pfd[i].fd));
261                                 PyTuple_SET_ITEM(it, 1, PyInt_FromLong(pfd[i].revents));
262                                 PyList_Append(*res, it);
263                                 Py_DECREF(it);
264                         }
265                 }
266         }
267         else if (ret < 0)
268         {
269                         /* when we got a signal, we get EINTR. */
270                 if (errno != EINTR)
271                         eDebug("poll made error (%m)");
272                 else
273                         return_reason = 2; /* don't assume the timeout has passed when we got a signal */
274         }
275
276         return return_reason;
277 }
278
279 void eMainloop::addTimer(eTimer* e)
280 {
281         m_timer_list.insert_in_order(e);
282 }
283
284 void eMainloop::removeTimer(eTimer* e)
285 {
286         m_timer_list.remove(e);
287 }
288
289 int eMainloop::iterate(unsigned int twisted_timeout, PyObject **res, ePyObject dict)
290 {
291         int ret = 0;
292
293         if (twisted_timeout)
294         {
295                 clock_gettime(CLOCK_MONOTONIC, &m_twisted_timer);
296                 m_twisted_timer += twisted_timeout;
297         }
298
299                 /* TODO: this code just became ugly. fix that. */
300         do
301         {
302                 if (m_interrupt_requested)
303                 {
304                         m_interrupt_requested = 0;
305                         return 0;
306                 }
307
308                 if (app_quit_now)
309                         return -1;
310
311                 int to = 0;
312                 if (twisted_timeout)
313                 {
314                         timespec now, timeout;
315                         clock_gettime(CLOCK_MONOTONIC, &now);
316                         if (m_twisted_timer<=now) // timeout
317                                 return 0;
318                         timeout = m_twisted_timer - now;
319                         to = timeout.tv_sec * 1000 + timeout.tv_nsec / 1000000;
320                 }
321                 ret = processOneEvent(to, res, dict);
322         } while ( !ret && !(res && *res) );
323
324         return ret;
325 }
326
327 int eMainloop::runLoop()
328 {
329         while (!app_quit_now)
330                 iterate();
331         return retval;
332 }
333
334 void eMainloop::reset()
335 {
336         app_quit_now=false;
337 }
338
339 PyObject *eMainloop::poll(ePyObject timeout, ePyObject dict)
340 {
341         PyObject *res=0;
342
343         if (app_quit_now)
344                 Py_RETURN_NONE;
345
346         int twisted_timeout = (timeout == Py_None) ? 0 : PyInt_AsLong(timeout);
347
348         iterate(twisted_timeout, &res, dict);
349         if (res)
350                 return res;
351
352         return PyList_New(0); /* return empty list on timeout */
353 }
354
355 void eMainloop::interruptPoll()
356 {
357         m_interrupt_requested = 1;
358 }
359
360 void eMainloop::quit(int ret)
361 {
362         retval = ret;
363         app_quit_now = true;
364 }
365
366 eApplication* eApp = 0;
367
368 #include "structmember.h"
369
370 extern "C" {
371
372 // eTimer replacement
373
374 struct eTimerPy
375 {
376         PyObject_HEAD
377         eTimer *tm;
378         PyObject *in_weakreflist; /* List of weak references */
379 };
380
381 static int
382 eTimerPy_traverse(eTimerPy *self, visitproc visit, void *arg)
383 {
384         PyObject *obj = self->tm->timeout.getSteal();
385         if (obj) {
386                 Py_VISIT(obj);
387         }
388         return 0;
389 }
390
391 static int
392 eTimerPy_clear(eTimerPy *self)
393 {
394         PyObject *obj = self->tm->timeout.getSteal(true);
395         if (obj)
396                 Py_CLEAR(obj);
397         return 0;
398 }
399
400 static void
401 eTimerPy_dealloc(eTimerPy* self)
402 {
403         if (self->in_weakreflist != NULL)
404                 PyObject_ClearWeakRefs((PyObject *) self);
405         eTimerPy_clear(self);
406         delete self->tm;
407         self->ob_type->tp_free((PyObject*)self);
408 }
409
410 static PyObject *
411 eTimerPy_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
412 {
413         eTimerPy *self = (eTimerPy *)type->tp_alloc(type, 0);
414         self->tm = new eTimer(eApp);
415         self->in_weakreflist = NULL;
416         return (PyObject *)self;
417 }
418
419 static PyObject *
420 eTimerPy_is_active(eTimerPy* self)
421 {
422         PyObject *ret = NULL;
423         ret = self->tm->isActive() ? Py_True : Py_False;
424         Org_Py_INCREF(ret);
425         return ret;
426 }
427
428 static PyObject *
429 eTimerPy_start(eTimerPy* self, PyObject *args)
430 {
431         long v=0;
432         long singleShot=0;
433         if (PyTuple_Size(args) > 1)
434         {
435                 if (!PyArg_ParseTuple(args, "ll", &v, &singleShot)) // when 2nd arg is a value
436                 {
437                         PyObject *obj=0;
438                         if (!PyArg_ParseTuple(args, "lO", &v, &obj)) // get 2nd arg as python object
439                                 return NULL;
440                         else if (obj == Py_True)
441                                 singleShot=1;
442                         else if (obj != Py_False)
443                                 return NULL;
444                 }
445         }
446         else if (!PyArg_ParseTuple(args, "l", &v))
447                 return NULL;
448         self->tm->start(v, singleShot);
449         Py_RETURN_NONE;
450 }
451
452 static PyObject *
453 eTimerPy_start_long(eTimerPy* self, PyObject *args)
454 {
455         int v=0;
456         if (!PyArg_ParseTuple(args, "i", &v)) {
457                 return NULL;
458         }
459         self->tm->startLongTimer(v);
460         Py_RETURN_NONE;
461 }
462
463 static PyObject *
464 eTimerPy_change_interval(eTimerPy* self, PyObject *args)
465 {
466         long v=0;
467         if (!PyArg_ParseTuple(args, "l", &v)) {
468                 return NULL;
469         }
470         self->tm->changeInterval(v);
471         Py_RETURN_NONE;
472 }
473
474 static PyObject *
475 eTimerPy_stop(eTimerPy* self)
476 {
477         self->tm->stop();
478         Py_RETURN_NONE;
479 }
480
481 static PyObject *
482 eTimerPy_get_callback_list(eTimerPy *self)
483 { //used for compatibilty with the old eTimer
484         return self->tm->timeout.get();
485 }
486
487 static PyMethodDef eTimerPy_methods[] = {
488         {"isActive", (PyCFunction)eTimerPy_is_active, METH_NOARGS,
489          "returns the timer state"
490         },
491         {"start", (PyCFunction)eTimerPy_start, METH_VARARGS,
492          "start timer with interval in msecs"
493         },
494         {"startLongTimer", (PyCFunction)eTimerPy_start_long, METH_VARARGS,
495          "start timer with interval in secs"
496         },
497         {"changeInterval", (PyCFunction)eTimerPy_change_interval, METH_VARARGS,
498          "change interval of a timer (in msecs)"
499         },
500         {"stop", (PyCFunction)eTimerPy_stop, METH_NOARGS,
501          "stops the timer"
502         },
503         //used for compatibilty with the old eTimer
504         {"get", (PyCFunction)eTimerPy_get_callback_list, METH_NOARGS,
505          "get timeout callback list"
506         },
507         {NULL}  /* Sentinel */
508 };
509
510 static PyObject *
511 eTimerPy_get_cb_list(eTimerPy *self, void *closure)
512 {
513         return self->tm->timeout.get();
514 }
515
516 static PyObject *
517 eTimerPy_timeout(eTimerPy *self, void *closure) 
518 { //used for compatibilty with the old eTimer
519         Org_Py_INCREF((PyObject*)self);
520         return (PyObject*)self;
521 }
522
523 static PyGetSetDef eTimerPy_getseters[] = {
524         {"callback",
525          (getter)eTimerPy_get_cb_list, (setter)0,
526          "returns the callback python list",
527          NULL},
528
529         {"timeout", //used for compatibilty with the old eTimer
530          (getter)eTimerPy_timeout, (setter)0,
531          "synonym for our self",
532          NULL},
533
534         {NULL} /* Sentinel */
535 };
536
537 static PyTypeObject eTimerPyType = {
538         PyObject_HEAD_INIT(NULL)
539         0, /*ob_size*/
540         "eBaseImpl.eTimer", /*tp_name*/
541         sizeof(eTimerPy), /*tp_basicsize*/
542         0, /*tp_itemsize*/
543         (destructor)eTimerPy_dealloc, /*tp_dealloc*/
544         0, /*tp_print*/
545         0, /*tp_getattr*/
546         0, /*tp_setattr*/
547         0, /*tp_compare*/
548         0, /*tp_repr*/
549         0, /*tp_as_number*/
550         0, /*tp_as_sequence*/
551         0, /*tp_as_mapping*/
552         0, /*tp_hash */
553         0, /*tp_call*/
554         0, /*tp_str*/
555         0, /*tp_getattro*/
556         0, /*tp_setattro*/
557         0, /*tp_as_buffer*/
558         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
559         "eTimer objects", /* tp_doc */
560         (traverseproc)eTimerPy_traverse, /* tp_traverse */
561         (inquiry)eTimerPy_clear, /* tp_clear */
562         0, /* tp_richcompare */
563         offsetof(eTimerPy, in_weakreflist), /* tp_weaklistoffset */
564         0, /* tp_iter */
565         0, /* tp_iternext */
566         eTimerPy_methods, /* tp_methods */
567         0, /* tp_members */
568         eTimerPy_getseters, /* tp_getset */
569         0, /* tp_base */
570         0, /* tp_dict */
571         0, /* tp_descr_get */
572         0, /* tp_descr_set */
573         0, /* tp_dictoffset */
574         0, /* tp_init */
575         0, /* tp_alloc */
576         eTimerPy_new, /* tp_new */
577 };
578
579 // eSocketNotifier replacement
580
581 struct eSocketNotifierPy
582 {
583         PyObject_HEAD
584         eSocketNotifier *sn;
585         PyObject *in_weakreflist; /* List of weak references */
586 };
587
588 static int
589 eSocketNotifierPy_traverse(eSocketNotifierPy *self, visitproc visit, void *arg)
590 {
591         PyObject *obj = self->sn->activated.getSteal();
592         if (obj)
593                 Py_VISIT(obj);
594         return 0;
595 }
596
597 static int
598 eSocketNotifierPy_clear(eSocketNotifierPy *self)
599 {
600         PyObject *obj = self->sn->activated.getSteal(true);
601         if (obj)
602                 Py_CLEAR(obj);
603         return 0;
604 }
605
606 static void
607 eSocketNotifierPy_dealloc(eSocketNotifierPy* self)
608 {
609         if (self->in_weakreflist != NULL)
610                 PyObject_ClearWeakRefs((PyObject *) self);
611         eSocketNotifierPy_clear(self);
612         self->sn->Release();
613         self->ob_type->tp_free((PyObject*)self);
614 }
615
616 static PyObject *
617 eSocketNotifierPy_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
618 {
619         eSocketNotifierPy *self = (eSocketNotifierPy *)type->tp_alloc(type, 0);
620         int fd, req, immediate_start = 1, size = PyTuple_Size(args);
621         if (size > 2)
622         {
623                 if (!PyArg_ParseTuple(args, "iii", &fd, &req, &immediate_start))
624                 {
625                         PyObject *obj = NULL;
626                         if (!PyArg_ParseTuple(args, "iiO", &fd, &req, &immediate_start))
627                                 return NULL;
628                         if (obj == Py_False)
629                                 immediate_start = 0;
630                         else if (obj != Py_True)
631                                 return NULL;
632                 }
633         }
634         else if (size < 2 || !PyArg_ParseTuple(args, "ii", &fd, &req))
635                 return NULL;
636         self->sn = eSocketNotifier::create(eApp, fd, req, immediate_start);
637         self->sn->AddRef();
638         self->in_weakreflist = NULL;
639         return (PyObject *)self;
640 }
641
642 static PyObject *
643 eSocketNotifierPy_is_running(eSocketNotifierPy* self)
644 {
645         PyObject *ret = self->sn->isRunning() ? Py_True : Py_False;
646         Org_Py_INCREF(ret);
647         return ret;
648 }
649
650 static PyObject *
651 eSocketNotifierPy_start(eSocketNotifierPy* self)
652 {
653         self->sn->start();
654         Py_RETURN_NONE;
655 }
656
657 static PyObject *
658 eSocketNotifierPy_stop(eSocketNotifierPy* self)
659 {
660         self->sn->stop();
661         Py_RETURN_NONE;
662 }
663
664 static PyObject *
665 eSocketNotifierPy_get_fd(eSocketNotifierPy* self)
666 {
667         return PyInt_FromLong(self->sn->getFD());
668 }
669
670 static PyObject *
671 eSocketNotifierPy_get_requested(eSocketNotifierPy* self)
672 {
673         return PyInt_FromLong(self->sn->getRequested());
674 }
675
676 static PyObject *
677 eSocketNotifierPy_set_requested(eSocketNotifierPy* self, PyObject *args)
678 {
679         int req;
680         if (PyTuple_Size(args) != 1 || !PyArg_ParseTuple(args, "i", &req))
681                 return NULL;
682         self->sn->setRequested(req);
683         Py_RETURN_NONE;
684 }
685
686 static PyMethodDef eSocketNotifierPy_methods[] = {
687         {"isRunning", (PyCFunction)eSocketNotifierPy_is_running, METH_NOARGS,
688          "returns the running state"
689         },
690         {"start", (PyCFunction)eSocketNotifierPy_start, METH_NOARGS,
691          "start the sn"
692         },
693         {"stop", (PyCFunction)eSocketNotifierPy_stop, METH_NOARGS,
694          "stops the sn"
695         },
696         {"getFD", (PyCFunction)eSocketNotifierPy_get_fd, METH_NOARGS,
697          "get file descriptor"
698         },
699         {"getRequested", (PyCFunction)eSocketNotifierPy_get_requested, METH_NOARGS,
700          "get requested"
701         },
702         {"setRequested", (PyCFunction)eSocketNotifierPy_set_requested, METH_VARARGS,
703          "set requested"
704         },
705         {NULL}  /* Sentinel */
706 };
707
708 static PyObject *
709 eSocketNotifierPy_get_cb_list(eSocketNotifierPy *self, void *closure)
710 {
711         return self->sn->activated.get();
712 }
713
714 static PyGetSetDef eSocketNotifierPy_getseters[] = {
715         {"callback",
716          (getter)eSocketNotifierPy_get_cb_list, (setter)0,
717          "returns the callback python list",
718          NULL},
719         {NULL} /* Sentinel */
720 };
721
722 static PyTypeObject eSocketNotifierPyType = {
723         PyObject_HEAD_INIT(NULL)
724         0, /*ob_size*/
725         "eBaseImpl.eSocketNotifier", /*tp_name*/
726         sizeof(eSocketNotifierPy), /*tp_basicsize*/
727         0, /*tp_itemsize*/
728         (destructor)eSocketNotifierPy_dealloc, /*tp_dealloc*/
729         0, /*tp_print*/
730         0, /*tp_getattr*/
731         0, /*tp_setattr*/
732         0, /*tp_compare*/
733         0, /*tp_repr*/
734         0, /*tp_as_number*/
735         0, /*tp_as_sequence*/
736         0, /*tp_as_mapping*/
737         0, /*tp_hash */
738         0, /*tp_call*/
739         0, /*tp_str*/
740         0, /*tp_getattro*/
741         0, /*tp_setattro*/
742         0, /*tp_as_buffer*/
743         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
744         "eTimer objects", /* tp_doc */
745         (traverseproc)eSocketNotifierPy_traverse, /* tp_traverse */
746         (inquiry)eSocketNotifierPy_clear, /* tp_clear */
747         0, /* tp_richcompare */
748         offsetof(eSocketNotifierPy, in_weakreflist), /* tp_weaklistoffset */
749         0, /* tp_iter */
750         0, /* tp_iternext */
751         eSocketNotifierPy_methods, /* tp_methods */
752         0, /* tp_members */
753         eSocketNotifierPy_getseters, /* tp_getset */
754         0, /* tp_base */
755         0, /* tp_dict */
756         0, /* tp_descr_get */
757         0, /* tp_descr_set */
758         0, /* tp_dictoffset */
759         0, /* tp_init */
760         0, /* tp_alloc */
761         eSocketNotifierPy_new, /* tp_new */
762 };
763
764 static PyMethodDef module_methods[] = {
765         {NULL}  /* Sentinel */
766 };
767
768 void eBaseInit(void)
769 {
770         PyObject* m = Py_InitModule3("eBaseImpl", module_methods,
771                 "Module that implements some enigma classes with working cyclic garbage collection.");
772
773         if (m == NULL)
774                 return;
775
776         if (!PyType_Ready(&eTimerPyType))
777         {
778                 Org_Py_INCREF((PyObject*)&eTimerPyType);
779                 PyModule_AddObject(m, "eTimer", (PyObject*)&eTimerPyType);
780         }
781         if (!PyType_Ready(&eSocketNotifierPyType))
782         {
783                 Org_Py_INCREF((PyObject*)&eSocketNotifierPyType);
784                 PyModule_AddObject(m, "eSocketNotifier", (PyObject*)&eSocketNotifierPyType);
785         }
786 }
787 }