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