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