Merge branch 'bug_411_timeshift_disable_without_live'
[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         ++m_idle_count;
229
230         if (this == eApp)
231         {
232                 gOpcode op;
233                 op.dc = 0;
234                 op.opcode = gOpcode::flush;
235                 gRC::getInstance()->submit(op);
236                 Py_BEGIN_ALLOW_THREADS
237                 ret = ::poll(pfd, fdcount, poll_timeout);
238                 Py_END_ALLOW_THREADS
239                 
240         } else
241                 ret = ::poll(pfd, fdcount, poll_timeout);
242
243         m_is_idle = 0;
244
245                         /* ret > 0 means that there are some active poll entries. */
246         if (ret > 0)
247         {
248                 int i=0;
249                 return_reason = 0;
250                 for (; i < nativecount; ++i)
251                 {
252                         if (pfd[i].revents)
253                         {
254                                 it = notifiers.find(pfd[i].fd);
255                                 if (it != notifiers.end()
256                                         && it->second->state == 1) // added and in poll
257                                 {
258                                         m_inActivate = it->second;
259                                         int req = m_inActivate->getRequested();
260                                         if (pfd[i].revents & req) {
261                                                 m_inActivate->AddRef();
262                                                 m_inActivate->activate(pfd[i].revents & req);
263                                                 m_inActivate->Release();
264                                         }
265                                         pfd[i].revents &= ~req;
266                                         m_inActivate = 0;
267                                 }
268                                 if (pfd[i].revents & (POLLERR|POLLHUP|POLLNVAL))
269                                         eDebug("poll: unhandled POLLERR/HUP/NVAL for fd %d(%d)", pfd[i].fd, pfd[i].revents);
270                         }
271                 }
272                 for (; i < fdcount; ++i)
273                 {
274                         if (pfd[i].revents)
275                         {
276                                 if (!*res)
277                                         *res = PyList_New(0);
278                                 ePyObject it = PyTuple_New(2);
279                                 PyTuple_SET_ITEM(it, 0, PyInt_FromLong(pfd[i].fd));
280                                 PyTuple_SET_ITEM(it, 1, PyInt_FromLong(pfd[i].revents));
281                                 PyList_Append(*res, it);
282                                 Py_DECREF(it);
283                         }
284                 }
285         }
286         else if (ret < 0)
287         {
288                         /* when we got a signal, we get EINTR. */
289                 if (errno != EINTR)
290                         eDebug("poll made error (%m)");
291                 else
292                         return_reason = 2; /* don't assume the timeout has passed when we got a signal */
293         }
294
295         return return_reason;
296 }
297
298 void eMainloop::addTimer(eTimer* e)
299 {
300         m_timer_list.insert_in_order(e);
301 }
302
303 void eMainloop::removeTimer(eTimer* e)
304 {
305         m_timer_list.remove(e);
306 }
307
308 int eMainloop::iterate(unsigned int twisted_timeout, PyObject **res, ePyObject dict)
309 {
310         int ret = 0;
311
312         if (twisted_timeout)
313         {
314                 clock_gettime(CLOCK_MONOTONIC, &m_twisted_timer);
315                 m_twisted_timer += twisted_timeout;
316         }
317
318                 /* TODO: this code just became ugly. fix that. */
319         do
320         {
321                 if (m_interrupt_requested)
322                 {
323                         m_interrupt_requested = 0;
324                         return 0;
325                 }
326
327                 if (app_quit_now)
328                         return -1;
329
330                 int to = 0;
331                 if (twisted_timeout)
332                 {
333                         timespec now, timeout;
334                         clock_gettime(CLOCK_MONOTONIC, &now);
335                         if (m_twisted_timer<=now) // timeout
336                                 return 0;
337                         timeout = m_twisted_timer - now;
338                         to = timeout.tv_sec * 1000 + timeout.tv_nsec / 1000000;
339                 }
340                 ret = processOneEvent(to, res, dict);
341         } while ( !ret && !(res && *res) );
342
343         return ret;
344 }
345
346 int eMainloop::runLoop()
347 {
348         while (!app_quit_now)
349                 iterate();
350         return retval;
351 }
352
353 void eMainloop::reset()
354 {
355         app_quit_now=false;
356 }
357
358 PyObject *eMainloop::poll(ePyObject timeout, ePyObject dict)
359 {
360         PyObject *res=0;
361
362         if (app_quit_now)
363                 Py_RETURN_NONE;
364
365         int twisted_timeout = (timeout == Py_None) ? 0 : PyInt_AsLong(timeout);
366
367         iterate(twisted_timeout, &res, dict);
368         if (res)
369                 return res;
370
371         return PyList_New(0); /* return empty list on timeout */
372 }
373
374 void eMainloop::interruptPoll()
375 {
376         m_interrupt_requested = 1;
377 }
378
379 void eMainloop::quit(int ret)
380 {
381         retval = ret;
382         app_quit_now = true;
383 }
384
385 eApplication* eApp = 0;
386
387 #include "structmember.h"
388
389 extern "C" {
390
391 // eTimer replacement
392
393 struct eTimerPy
394 {
395         PyObject_HEAD
396         eTimer *tm;
397         PyObject *in_weakreflist; /* List of weak references */
398 };
399
400 static int
401 eTimerPy_traverse(eTimerPy *self, visitproc visit, void *arg)
402 {
403         PyObject *obj = self->tm->timeout.getSteal();
404         if (obj) {
405                 Py_VISIT(obj);
406         }
407         return 0;
408 }
409
410 static int
411 eTimerPy_clear(eTimerPy *self)
412 {
413         PyObject *obj = self->tm->timeout.getSteal(true);
414         if (obj)
415                 Py_CLEAR(obj);
416         return 0;
417 }
418
419 static void
420 eTimerPy_dealloc(eTimerPy* self)
421 {
422         if (self->in_weakreflist != NULL)
423                 PyObject_ClearWeakRefs((PyObject *) self);
424         eTimerPy_clear(self);
425         self->tm->Release();
426         self->ob_type->tp_free((PyObject*)self);
427 }
428
429 static PyObject *
430 eTimerPy_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
431 {
432         eTimerPy *self = (eTimerPy *)type->tp_alloc(type, 0);
433         self->tm = eTimer::create(eApp);
434         self->tm->AddRef();
435         self->in_weakreflist = NULL;
436         return (PyObject *)self;
437 }
438
439 static PyObject *
440 eTimerPy_is_active(eTimerPy* self)
441 {
442         PyObject *ret = NULL;
443         ret = self->tm->isActive() ? Py_True : Py_False;
444         Org_Py_INCREF(ret);
445         return ret;
446 }
447
448 static PyObject *
449 eTimerPy_start(eTimerPy* self, PyObject *args)
450 {
451         long v=0;
452         long singleShot=0;
453         if (PyTuple_Size(args) > 1)
454         {
455                 if (!PyArg_ParseTuple(args, "ll", &v, &singleShot)) // when 2nd arg is a value
456                 {
457                         PyObject *obj=0;
458                         if (!PyArg_ParseTuple(args, "lO", &v, &obj)) // get 2nd arg as python object
459                                 return NULL;
460                         else if (obj == Py_True)
461                                 singleShot=1;
462                         else if (obj != Py_False)
463                                 return NULL;
464                 }
465         }
466         else if (!PyArg_ParseTuple(args, "l", &v))
467                 return NULL;
468         self->tm->start(v, singleShot);
469         Py_RETURN_NONE;
470 }
471
472 static PyObject *
473 eTimerPy_start_long(eTimerPy* self, PyObject *args)
474 {
475         int v=0;
476         if (!PyArg_ParseTuple(args, "i", &v)) {
477                 return NULL;
478         }
479         self->tm->startLongTimer(v);
480         Py_RETURN_NONE;
481 }
482
483 static PyObject *
484 eTimerPy_change_interval(eTimerPy* self, PyObject *args)
485 {
486         long v=0;
487         if (!PyArg_ParseTuple(args, "l", &v)) {
488                 return NULL;
489         }
490         self->tm->changeInterval(v);
491         Py_RETURN_NONE;
492 }
493
494 static PyObject *
495 eTimerPy_stop(eTimerPy* self)
496 {
497         self->tm->stop();
498         Py_RETURN_NONE;
499 }
500
501 static PyObject *
502 eTimerPy_get_callback_list(eTimerPy *self)
503 { //used for compatibilty with the old eTimer
504         return self->tm->timeout.get();
505 }
506
507 static PyMethodDef eTimerPy_methods[] = {
508         {"isActive", (PyCFunction)eTimerPy_is_active, METH_NOARGS,
509          "returns the timer state"
510         },
511         {"start", (PyCFunction)eTimerPy_start, METH_VARARGS,
512          "start timer with interval in msecs"
513         },
514         {"startLongTimer", (PyCFunction)eTimerPy_start_long, METH_VARARGS,
515          "start timer with interval in secs"
516         },
517         {"changeInterval", (PyCFunction)eTimerPy_change_interval, METH_VARARGS,
518          "change interval of a timer (in msecs)"
519         },
520         {"stop", (PyCFunction)eTimerPy_stop, METH_NOARGS,
521          "stops the timer"
522         },
523         //used for compatibilty with the old eTimer
524         {"get", (PyCFunction)eTimerPy_get_callback_list, METH_NOARGS,
525          "get timeout callback list"
526         },
527         {NULL}  /* Sentinel */
528 };
529
530 static PyObject *
531 eTimerPy_get_cb_list(eTimerPy *self, void *closure)
532 {
533         return self->tm->timeout.get();
534 }
535
536 static PyObject *
537 eTimerPy_timeout(eTimerPy *self, void *closure) 
538 { //used for compatibilty with the old eTimer
539         Org_Py_INCREF((PyObject*)self);
540         return (PyObject*)self;
541 }
542
543 static PyGetSetDef eTimerPy_getseters[] = {
544         {"callback",
545          (getter)eTimerPy_get_cb_list, (setter)0,
546          "returns the callback python list",
547          NULL},
548
549         {"timeout", //used for compatibilty with the old eTimer
550          (getter)eTimerPy_timeout, (setter)0,
551          "synonym for our self",
552          NULL},
553
554         {NULL} /* Sentinel */
555 };
556
557 static PyTypeObject eTimerPyType = {
558         PyObject_HEAD_INIT(NULL)
559         0, /*ob_size*/
560         "eBaseImpl.eTimer", /*tp_name*/
561         sizeof(eTimerPy), /*tp_basicsize*/
562         0, /*tp_itemsize*/
563         (destructor)eTimerPy_dealloc, /*tp_dealloc*/
564         0, /*tp_print*/
565         0, /*tp_getattr*/
566         0, /*tp_setattr*/
567         0, /*tp_compare*/
568         0, /*tp_repr*/
569         0, /*tp_as_number*/
570         0, /*tp_as_sequence*/
571         0, /*tp_as_mapping*/
572         0, /*tp_hash */
573         0, /*tp_call*/
574         0, /*tp_str*/
575         0, /*tp_getattro*/
576         0, /*tp_setattro*/
577         0, /*tp_as_buffer*/
578         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
579         "eTimer objects", /* tp_doc */
580         (traverseproc)eTimerPy_traverse, /* tp_traverse */
581         (inquiry)eTimerPy_clear, /* tp_clear */
582         0, /* tp_richcompare */
583         offsetof(eTimerPy, in_weakreflist), /* tp_weaklistoffset */
584         0, /* tp_iter */
585         0, /* tp_iternext */
586         eTimerPy_methods, /* tp_methods */
587         0, /* tp_members */
588         eTimerPy_getseters, /* tp_getset */
589         0, /* tp_base */
590         0, /* tp_dict */
591         0, /* tp_descr_get */
592         0, /* tp_descr_set */
593         0, /* tp_dictoffset */
594         0, /* tp_init */
595         0, /* tp_alloc */
596         eTimerPy_new, /* tp_new */
597 };
598
599 // eSocketNotifier replacement
600
601 struct eSocketNotifierPy
602 {
603         PyObject_HEAD
604         eSocketNotifier *sn;
605         PyObject *in_weakreflist; /* List of weak references */
606 };
607
608 static int
609 eSocketNotifierPy_traverse(eSocketNotifierPy *self, visitproc visit, void *arg)
610 {
611         PyObject *obj = self->sn->activated.getSteal();
612         if (obj)
613                 Py_VISIT(obj);
614         return 0;
615 }
616
617 static int
618 eSocketNotifierPy_clear(eSocketNotifierPy *self)
619 {
620         PyObject *obj = self->sn->activated.getSteal(true);
621         if (obj)
622                 Py_CLEAR(obj);
623         return 0;
624 }
625
626 static void
627 eSocketNotifierPy_dealloc(eSocketNotifierPy* self)
628 {
629         if (self->in_weakreflist != NULL)
630                 PyObject_ClearWeakRefs((PyObject *) self);
631         eSocketNotifierPy_clear(self);
632         self->sn->Release();
633         self->ob_type->tp_free((PyObject*)self);
634 }
635
636 static PyObject *
637 eSocketNotifierPy_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
638 {
639         eSocketNotifierPy *self = (eSocketNotifierPy *)type->tp_alloc(type, 0);
640         int fd, req, immediate_start = 1, size = PyTuple_Size(args);
641         if (size > 2)
642         {
643                 if (!PyArg_ParseTuple(args, "iii", &fd, &req, &immediate_start))
644                 {
645                         PyObject *obj = NULL;
646                         if (!PyArg_ParseTuple(args, "iiO", &fd, &req, &immediate_start))
647                                 return NULL;
648                         if (obj == Py_False)
649                                 immediate_start = 0;
650                         else if (obj != Py_True)
651                                 return NULL;
652                 }
653         }
654         else if (size < 2 || !PyArg_ParseTuple(args, "ii", &fd, &req))
655                 return NULL;
656         self->sn = eSocketNotifier::create(eApp, fd, req, immediate_start);
657         self->sn->AddRef();
658         self->in_weakreflist = NULL;
659         return (PyObject *)self;
660 }
661
662 static PyObject *
663 eSocketNotifierPy_is_running(eSocketNotifierPy* self)
664 {
665         PyObject *ret = self->sn->isRunning() ? Py_True : Py_False;
666         Org_Py_INCREF(ret);
667         return ret;
668 }
669
670 static PyObject *
671 eSocketNotifierPy_start(eSocketNotifierPy* self)
672 {
673         self->sn->start();
674         Py_RETURN_NONE;
675 }
676
677 static PyObject *
678 eSocketNotifierPy_stop(eSocketNotifierPy* self)
679 {
680         self->sn->stop();
681         Py_RETURN_NONE;
682 }
683
684 static PyObject *
685 eSocketNotifierPy_get_fd(eSocketNotifierPy* self)
686 {
687         return PyInt_FromLong(self->sn->getFD());
688 }
689
690 static PyObject *
691 eSocketNotifierPy_get_requested(eSocketNotifierPy* self)
692 {
693         return PyInt_FromLong(self->sn->getRequested());
694 }
695
696 static PyObject *
697 eSocketNotifierPy_set_requested(eSocketNotifierPy* self, PyObject *args)
698 {
699         int req;
700         if (PyTuple_Size(args) != 1 || !PyArg_ParseTuple(args, "i", &req))
701                 return NULL;
702         self->sn->setRequested(req);
703         Py_RETURN_NONE;
704 }
705
706 static PyMethodDef eSocketNotifierPy_methods[] = {
707         {"isRunning", (PyCFunction)eSocketNotifierPy_is_running, METH_NOARGS,
708          "returns the running state"
709         },
710         {"start", (PyCFunction)eSocketNotifierPy_start, METH_NOARGS,
711          "start the sn"
712         },
713         {"stop", (PyCFunction)eSocketNotifierPy_stop, METH_NOARGS,
714          "stops the sn"
715         },
716         {"getFD", (PyCFunction)eSocketNotifierPy_get_fd, METH_NOARGS,
717          "get file descriptor"
718         },
719         {"getRequested", (PyCFunction)eSocketNotifierPy_get_requested, METH_NOARGS,
720          "get requested"
721         },
722         {"setRequested", (PyCFunction)eSocketNotifierPy_set_requested, METH_VARARGS,
723          "set requested"
724         },
725         {NULL}  /* Sentinel */
726 };
727
728 static PyObject *
729 eSocketNotifierPy_get_cb_list(eSocketNotifierPy *self, void *closure)
730 {
731         return self->sn->activated.get();
732 }
733
734 static PyGetSetDef eSocketNotifierPy_getseters[] = {
735         {"callback",
736          (getter)eSocketNotifierPy_get_cb_list, (setter)0,
737          "returns the callback python list",
738          NULL},
739         {NULL} /* Sentinel */
740 };
741
742 static PyTypeObject eSocketNotifierPyType = {
743         PyObject_HEAD_INIT(NULL)
744         0, /*ob_size*/
745         "eBaseImpl.eSocketNotifier", /*tp_name*/
746         sizeof(eSocketNotifierPy), /*tp_basicsize*/
747         0, /*tp_itemsize*/
748         (destructor)eSocketNotifierPy_dealloc, /*tp_dealloc*/
749         0, /*tp_print*/
750         0, /*tp_getattr*/
751         0, /*tp_setattr*/
752         0, /*tp_compare*/
753         0, /*tp_repr*/
754         0, /*tp_as_number*/
755         0, /*tp_as_sequence*/
756         0, /*tp_as_mapping*/
757         0, /*tp_hash */
758         0, /*tp_call*/
759         0, /*tp_str*/
760         0, /*tp_getattro*/
761         0, /*tp_setattro*/
762         0, /*tp_as_buffer*/
763         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
764         "eTimer objects", /* tp_doc */
765         (traverseproc)eSocketNotifierPy_traverse, /* tp_traverse */
766         (inquiry)eSocketNotifierPy_clear, /* tp_clear */
767         0, /* tp_richcompare */
768         offsetof(eSocketNotifierPy, in_weakreflist), /* tp_weaklistoffset */
769         0, /* tp_iter */
770         0, /* tp_iternext */
771         eSocketNotifierPy_methods, /* tp_methods */
772         0, /* tp_members */
773         eSocketNotifierPy_getseters, /* tp_getset */
774         0, /* tp_base */
775         0, /* tp_dict */
776         0, /* tp_descr_get */
777         0, /* tp_descr_set */
778         0, /* tp_dictoffset */
779         0, /* tp_init */
780         0, /* tp_alloc */
781         eSocketNotifierPy_new, /* tp_new */
782 };
783
784 static PyMethodDef module_methods[] = {
785         {NULL}  /* Sentinel */
786 };
787
788 void eBaseInit(void)
789 {
790         PyObject* m = Py_InitModule3("eBaseImpl", module_methods,
791                 "Module that implements some enigma classes with working cyclic garbage collection.");
792
793         if (m == NULL)
794                 return;
795
796         if (!PyType_Ready(&eTimerPyType))
797         {
798                 Org_Py_INCREF((PyObject*)&eTimerPyType);
799                 PyModule_AddObject(m, "eTimer", (PyObject*)&eTimerPyType);
800         }
801         if (!PyType_Ready(&eSocketNotifierPyType))
802         {
803                 Org_Py_INCREF((PyObject*)&eSocketNotifierPyType);
804                 PyModule_AddObject(m, "eSocketNotifier", (PyObject*)&eSocketNotifierPyType);
805         }
806 }
807 }