PageRenderTime 45ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/tobikko/core/event.c

https://bitbucket.org/mopemope/tobikko/
C | 398 lines | 353 code | 42 blank | 3 comment | 57 complexity | ffb0a6b398612c9f634da615a5cc7feb MD5 | raw file
  1. #include "event.h"
  2. #include "hub.h"
  3. #include "greensupport.h"
  4. #include "timer.h"
  5. static PyObject *notify_func = NULL;
  6. static PyObject* get_notify(void);
  7. static int
  8. EventObject_init(EventObject *self, PyObject *args, PyObject *kwargs)
  9. {
  10. int ret = 0;
  11. PyObject *waiters, *links;
  12. waiters = PySet_New(NULL);
  13. if(waiters == NULL){
  14. return -1;
  15. }
  16. links = PySet_New(NULL);
  17. if(links == NULL){
  18. Py_DECREF(waiters);
  19. return -1;
  20. }
  21. if(self->waiters){
  22. Py_CLEAR(self->waiters);
  23. }
  24. if(self->links){
  25. Py_CLEAR(self->links);
  26. }
  27. self->waiters = waiters;
  28. self->links = links;
  29. self->flag = 0;
  30. RDEBUG("self:%p", self);
  31. return ret;
  32. }
  33. static int
  34. EventObject_clear(EventObject *self)
  35. {
  36. DEBUG("self:%p", self);
  37. Py_CLEAR(self->waiters);
  38. Py_CLEAR(self->links);
  39. Py_CLEAR(self->notify_timer);
  40. return 0;
  41. }
  42. static int
  43. EventObject_traverse(EventObject *self, visitproc visit, void *arg)
  44. {
  45. DEBUG("self:%p cnt:%d", self, (int)Py_REFCNT(self));
  46. DEBUG("waiters:%d links:%d", (int)PySet_GET_SIZE(self->waiters), (int)PySet_GET_SIZE(self->links));
  47. Py_VISIT(self->links);
  48. Py_VISIT(self->waiters);
  49. Py_VISIT(self->notify_timer);
  50. return 0;
  51. }
  52. static void
  53. EventObject_dealloc(EventObject *self)
  54. {
  55. RDEBUG("self:%p", self);
  56. PyObject_GC_UnTrack(self);
  57. Py_TRASHCAN_SAFE_BEGIN(self);
  58. EventObject_clear(self);
  59. Py_TYPE(self)->tp_free((PyObject*)self);
  60. Py_TRASHCAN_SAFE_END(self);
  61. }
  62. static int
  63. notify_to_hub(EventObject *self, PyObject *callable, PyObject *args)
  64. {
  65. TimerObject *t;
  66. DEBUG("self->notify_timer %p", self->notify_timer);
  67. if(!self->notify_timer){
  68. t = (TimerObject*)hub_schedule_call(0, callable, args, NULL, NULL);
  69. if(t == NULL){
  70. return 0;
  71. }
  72. self->notify_timer = (PyObject*)t;
  73. }else{
  74. t = (TimerObject*)self->notify_timer;
  75. DEBUG("notify_timer called ? %d", t->called);
  76. if(t->called){
  77. Py_CLEAR(self->notify_timer);
  78. t = (TimerObject*)hub_schedule_call(0, callable, args, NULL, NULL);
  79. if(t == NULL){
  80. return 0;
  81. }
  82. self->notify_timer = (PyObject*)t;
  83. }else{
  84. DEBUG("Not yet calll notify");
  85. }
  86. }
  87. return 1;
  88. }
  89. static int
  90. check_exception_timer(TimerObject *timer)
  91. {
  92. int ret = 0;
  93. PyObject *type, *value, *traceback;
  94. TimerObject *exc_timer;
  95. if(timer == NULL){
  96. return ret;
  97. }
  98. PyErr_Fetch(&type, &value, &traceback);
  99. if(PyObject_HasAttrString(value, "timer")){
  100. exc_timer = (TimerObject*)PyObject_GetAttrString(value, "timer");
  101. if(exc_timer == timer){
  102. ret = 1;
  103. }
  104. }
  105. if(ret){
  106. Py_XDECREF(type);
  107. Py_XDECREF(value);
  108. Py_XDECREF(traceback);
  109. }else{
  110. PyErr_Restore(type, value, traceback);
  111. }
  112. return ret;
  113. }
  114. static PyObject*
  115. EventObject_rawlink(EventObject *self, PyObject *callable)
  116. {
  117. PyObject *args = NULL;
  118. DEBUG("self:%p", self);
  119. if(!callable || !PyCallable_Check(callable)){
  120. PyErr_SetString(PyExc_TypeError, "must be callable");
  121. return NULL;
  122. }
  123. if(PySet_Add(self->links, callable) == -1){
  124. return NULL;
  125. }
  126. if(self->flag && !is_active_timer((TimerObject*)self->notify_timer)){
  127. if(PySet_Add(self->waiters, callable) == -1){
  128. return NULL;
  129. }
  130. args = Py_BuildValue("(O)", self);
  131. //DEBUG("args:%p", args);
  132. if(!notify_to_hub(self, get_notify(), args)){
  133. Py_DECREF(args);
  134. return NULL;
  135. }
  136. Py_DECREF(args);
  137. }
  138. Py_RETURN_NONE;
  139. }
  140. static PyObject*
  141. EventObject_unlink(EventObject *self, PyObject *callable)
  142. {
  143. DEBUG("self:%p self->waiters:%p", self, self->waiters);
  144. if(PySet_Discard(self->links, callable) == -1){
  145. if(PyErr_Occurred()){
  146. PyErr_Clear();
  147. }
  148. }
  149. Py_RETURN_NONE;
  150. }
  151. static PyObject*
  152. internal_set(EventObject *self)
  153. {
  154. PyObject *ret;
  155. PyObject *args = NULL;
  156. self->flag = 1;
  157. ret = PyNumber_InPlaceOr(self->waiters, self->links);
  158. //DEBUG("waiters:%p ret:%p", self->waiters, ret);
  159. if(ret == NULL) {
  160. return NULL;
  161. }
  162. Py_DECREF(ret);
  163. if(PySet_GET_SIZE(self->waiters) > 0){
  164. args = Py_BuildValue("(O)", self);
  165. //DEBUG("args:%p", args);
  166. if(!notify_to_hub(self, get_notify(), args)){
  167. Py_DECREF(args);
  168. return NULL;
  169. }
  170. Py_DECREF(args);
  171. }
  172. Py_RETURN_NONE;
  173. }
  174. PyObject*
  175. event_set(EventObject *self)
  176. {
  177. return internal_set(self);
  178. }
  179. static PyObject*
  180. EventObject_set(EventObject *self, PyObject *args)
  181. {
  182. return internal_set(self);
  183. }
  184. static PyObject*
  185. EventObject_reset(EventObject *self, PyObject *args)
  186. {
  187. self->flag = 0;
  188. Py_RETURN_NONE;
  189. }
  190. static PyObject*
  191. internal_wait(EventObject *self, int timeout)
  192. {
  193. PyObject *current, *s, *ret, *unlinkret;
  194. TimerObject *t = NULL;
  195. int success = 1;
  196. ret = Py_False;
  197. if(!self->flag){
  198. current = (PyObject*)greenlet_getcurrent();
  199. s = PyObject_GetAttrString((PyObject*)current, "switch");
  200. ret = EventObject_rawlink(self, s);
  201. Py_XDECREF(ret);
  202. Py_DECREF(s);
  203. Py_DECREF(current);
  204. if(ret == NULL){
  205. return NULL;
  206. }
  207. if(timeout > 0){
  208. t = (TimerObject*)hub_set_timeout(timeout, NULL);
  209. if(t == NULL){
  210. return NULL;
  211. }
  212. }
  213. ret = hub_switch();
  214. Py_CLEAR(ret);
  215. if(t){
  216. t->called = 1;
  217. Py_DECREF(t);
  218. }
  219. if(PyErr_Occurred()){
  220. success = 0;
  221. DEBUG("PyErr_Occurred");
  222. if(PyErr_ExceptionMatches(TimeoutException)){
  223. DEBUG("TimeoutException");
  224. if(check_exception_timer(t)){
  225. success = 1;
  226. }else{
  227. RDEBUG("raise TimeoutException");
  228. ret = NULL;
  229. }
  230. }else{
  231. ret = NULL;
  232. }
  233. }
  234. unlinkret = EventObject_unlink(self, s);
  235. Py_XDECREF(unlinkret);
  236. }
  237. if(success){
  238. ret = self->flag == 1 ? Py_True : Py_False;
  239. Py_INCREF(ret);
  240. }
  241. return ret;
  242. }
  243. PyObject*
  244. event_wait(EventObject *self, int timeout)
  245. {
  246. return internal_wait(self, timeout);
  247. }
  248. static PyObject*
  249. EventObject_wait(EventObject *self, PyObject *args, PyObject *kwargs)
  250. {
  251. int timeout = 0;
  252. static char *keywords[] = {"timeout", NULL};
  253. if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:wait", keywords, &timeout)){
  254. return NULL;
  255. }
  256. if(timeout < 0){
  257. PyErr_SetString(PyExc_TypeError, "timeout value out of range");
  258. return NULL;
  259. }
  260. return internal_wait(self, timeout);
  261. }
  262. static PyObject*
  263. EventObject_notify(EventObject *self, PyObject *args)
  264. {
  265. PyObject *o = NULL, *ret, *type, *value, *traceback;
  266. int contains = -1;
  267. self = (EventObject*)PyTuple_GET_ITEM(args, 0);
  268. DEBUG("self:%p", self);
  269. while(1){
  270. o = PySet_Pop(self->waiters);
  271. if(o == NULL){
  272. PyErr_Clear();
  273. break;
  274. }
  275. contains = PySet_Contains(self->links, o);
  276. if(contains == -1){
  277. Py_DECREF(o);
  278. return NULL;
  279. }else if(contains == 1){
  280. ret = PyObject_CallObject(o, args);
  281. Py_XDECREF(ret);
  282. if(PyErr_Occurred()){
  283. PyErr_Fetch(&type, &value, &traceback);
  284. PyErr_Clear();
  285. ret = hub_handle_error((PyObject*)self, type, value, traceback);
  286. Py_XDECREF(ret);
  287. }
  288. }
  289. Py_XDECREF(o);
  290. }
  291. Py_XDECREF(self);
  292. Py_RETURN_NONE;
  293. }
  294. static PyMethodDef EventObject_methods[] = {
  295. {"set", (PyCFunction)EventObject_set, METH_NOARGS, 0},
  296. {"reset", (PyCFunction)EventObject_reset, METH_NOARGS, 0},
  297. {"clear", (PyCFunction)EventObject_reset, METH_NOARGS, 0},
  298. {"wait", (PyCFunction)EventObject_wait, METH_VARARGS|METH_KEYWORDS, 0},
  299. {NULL, NULL} /* sentinel */
  300. };
  301. static PyMethodDef notify_func_def = {"notify", (PyCFunction)EventObject_notify, METH_VARARGS, 0};
  302. static PyObject*
  303. get_notify(void)
  304. {
  305. if(notify_func == NULL){
  306. notify_func = PyCFunction_NewEx(&notify_func_def, (PyObject *)NULL, NULL);
  307. }
  308. Py_INCREF(notify_func);
  309. return notify_func;
  310. }
  311. PyTypeObject EventObjectType = {
  312. #ifdef PY3
  313. PyVarObject_HEAD_INIT(NULL, 0)
  314. #else
  315. PyObject_HEAD_INIT(NULL)
  316. 0, /* ob_size */
  317. #endif
  318. MODULE_NAME ".core.Event", /*tp_name*/
  319. sizeof(EventObject), /*tp_basicsize*/
  320. 0, /*tp_itemsize*/
  321. (destructor)EventObject_dealloc, /*tp_dealloc*/
  322. 0, /*tp_print*/
  323. 0, /*tp_getattr*/
  324. 0, /*tp_setattr*/
  325. 0, /*tp_compare*/
  326. 0, /*tp_repr*/
  327. 0, /*tp_as_number*/
  328. 0, /*tp_as_sequence*/
  329. 0, /*tp_as_mapping*/
  330. 0, /*tp_hash */
  331. 0, /*tp_call*/
  332. 0, /*tp_str*/
  333. 0, /*tp_getattro*/
  334. 0, /*tp_setattro*/
  335. 0, /*tp_as_buffer*/
  336. Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, /*tp_flags*/
  337. "EventObject", /* tp_doc */
  338. (traverseproc)EventObject_traverse, /* tp_traverse */
  339. (inquiry)EventObject_clear, /* tp_clear */
  340. 0, /* tp_richcompare */
  341. 0, /* tp_weaklistoffset */
  342. 0, /* tp_iter */
  343. 0, /* tp_iternext */
  344. EventObject_methods, /* tp_methods */
  345. 0, /* tp_members */
  346. 0, /* tp_getset */
  347. 0, /* tp_base */
  348. 0, /* tp_dict */
  349. 0, /* tp_descr_get */
  350. 0, /* tp_descr_set */
  351. 0, /* tp_dictoffset */
  352. (initproc)EventObject_init, /* tp_init */
  353. PyType_GenericAlloc, /* tp_alloc */
  354. 0, /* tp_new */
  355. PyObject_GC_Del, /* tp_free */
  356. };