PageRenderTime 2813ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/tobikko/core/hub.c

https://bitbucket.org/mopemope/tobikko/
C | 1224 lines | 989 code | 157 blank | 78 comment | 186 complexity | 5bb206c9a96b2240e197662c3ad76c35 MD5 | raw file
  1. #include "hub.h"
  2. #include "timer.h"
  3. #include "heapq.h"
  4. #include "lookup.h"
  5. #include "buffer.h"
  6. #include "socket.h"
  7. #include "greensupport.h"
  8. #include <assert.h>
  9. typedef struct {
  10. TimerObject **q;
  11. uint32_t size;
  12. uint32_t max;
  13. } pending_queue_t;
  14. typedef struct {
  15. PyGreenlet *greenlet;
  16. PyObject *timeout_exc;
  17. } switch_arg_t;
  18. //loop start flag
  19. static volatile sig_atomic_t loop_done;
  20. static volatile sig_atomic_t catch_signal = 0;
  21. //force stop flag
  22. static uint8_t stopped = 0;
  23. static uint8_t debug = 0;
  24. static uint32_t activecnt = 0;
  25. static uint32_t ioactivecnt = 0;
  26. static heapq_t *g_timers;
  27. static pending_queue_t *g_pendings = NULL;
  28. //static HubObject *hub = NULL;
  29. static PyObject *watchdog = NULL;
  30. static PyGreenlet *suspend_thread = NULL;
  31. static PyObject *system_errors;
  32. static PyObject *sleep_callback = NULL;
  33. //special switch value
  34. static int internal_init_hub_thread(HubObject *self);
  35. static inline PyObject* internal_hub_schedule_call(int seconds, PyObject *cb, PyObject *args, PyObject *kwargs, PyGreenlet *greenlet);
  36. static inline HubObject* internal_get_hub(void);
  37. static void
  38. sigint_cb(int signum)
  39. {
  40. DEBUG("call SIGINT");
  41. loop_done = 0;
  42. RDEBUG("loop_done = 0");
  43. if(!catch_signal){
  44. catch_signal = 1;
  45. }
  46. //hub_abort();
  47. }
  48. static void
  49. sigpipe_cb(int signum)
  50. {
  51. }
  52. static int
  53. init_pendings(void)
  54. {
  55. pending_queue_t *pendings = NULL;
  56. pendings = PyMem_Malloc(sizeof(pending_queue_t));
  57. if(pendings == NULL){
  58. return -1;
  59. }
  60. pendings->size = 0;
  61. pendings->max= 1024;
  62. pendings->q = (TimerObject**)malloc(sizeof(TimerObject*) * pendings->max);
  63. if(pendings->q == NULL){
  64. PyMem_Free(pendings);
  65. return -1;
  66. }
  67. g_pendings = pendings;
  68. return 1;
  69. }
  70. static int
  71. realloc_pendings(void)
  72. {
  73. TimerObject **new_heap;
  74. uint32_t max;
  75. pending_queue_t *pendings = g_pendings;
  76. if(pendings->size >= pendings->max){
  77. //realloc
  78. max = pendings->max * 2;
  79. new_heap = (TimerObject**)realloc(pendings->q, sizeof(TimerObject*) * max);
  80. if(new_heap == NULL){
  81. PyErr_SetString(PyExc_Exception, "size over timer queue");
  82. return -1;
  83. }
  84. pendings->max = max;
  85. pendings->q = new_heap;
  86. RDEBUG("realloc max:%d", pendings->max);
  87. }
  88. return 1;
  89. }
  90. static void
  91. destroy_pendings(void)
  92. {
  93. if(g_pendings == NULL){
  94. return;
  95. }
  96. /*
  97. int i = pendings->start;
  98. int len = pendings->size - i;
  99. TimerObject *timer = NULL;
  100. TimerObject **t = pendings->q;
  101. t += i;
  102. while(len--){
  103. timer = *t;
  104. Py_DECREF(timer);
  105. pendings->start++;
  106. t++;
  107. }*/
  108. free(g_pendings->q);
  109. PyMem_Free(g_pendings);
  110. g_pendings = NULL;
  111. }
  112. void
  113. reset_all(void)
  114. {
  115. //Py_XDECREF(hub);
  116. //hub = NULL;
  117. //TODO error check
  118. destroy_queue(g_timers);
  119. g_timers = init_queue();
  120. destroy_pendings();
  121. init_pendings();
  122. (void)reset_channel();
  123. //set sig again
  124. PyOS_setsig(SIGPIPE, sigpipe_cb);
  125. PyOS_setsig(SIGINT, sigint_cb);
  126. PyOS_setsig(SIGTERM, sigint_cb);
  127. reset_main_loop();
  128. }
  129. static inline int
  130. fire_pendings(void)
  131. {
  132. PyObject *res;
  133. TimerObject *timer = NULL;
  134. pending_queue_t *pendings = g_pendings;
  135. while(pendings->size && loop_done){
  136. timer = *(pendings->q + --pendings->size);
  137. DEBUG("start timer:%p activecnt:%d", timer, activecnt);
  138. if(!timer->called){
  139. timer->called = 1;
  140. res = PyObject_Call(timer->callback, timer->args, timer->kwargs);
  141. Py_XDECREF(res);
  142. DEBUG("call pending %p", timer);
  143. }
  144. Py_DECREF(timer);
  145. activecnt--;
  146. DEBUG("fin timer:%p activecnt:%d", timer, activecnt);
  147. if(PyErr_Occurred()){
  148. RDEBUG("pending call raise exception");
  149. if(debug){
  150. //TODO PyErr_Print or write log
  151. PyErr_Print();
  152. }else{
  153. return -1;
  154. }
  155. }
  156. }
  157. return 1;
  158. }
  159. static inline int
  160. fire_timer(void)
  161. {
  162. TimerObject *timer;
  163. int ret = 1;
  164. heapq_t *q = g_timers;
  165. time_t now = time(NULL);
  166. PyObject *res = NULL;
  167. while(q->size > 0 && loop_done){
  168. timer = q->heap[0];
  169. if(timer->seconds <= now){
  170. //call
  171. if(!timer->called){
  172. timer->called = 1;
  173. if(timer->greenlet){
  174. //local timer
  175. if(!greenlet_dead(timer->greenlet)){
  176. res = PyObject_Call(timer->callback, timer->args, timer->kwargs);
  177. }
  178. } else{
  179. res = PyObject_Call(timer->callback, timer->args, timer->kwargs);
  180. }
  181. Py_XDECREF(res);
  182. }
  183. timer = heappop(q);
  184. Py_DECREF(timer);
  185. activecnt--;
  186. if(PyErr_Occurred()){
  187. RDEBUG("scheduled call raise exception");
  188. if(debug){
  189. //TODO PyErr_Print or write log
  190. PyErr_Print();
  191. }else{
  192. ret = -1;
  193. break;
  194. }
  195. }
  196. }else{
  197. break;
  198. }
  199. }
  200. return ret;
  201. }
  202. static void
  203. init_main_loop(HubObject *self)
  204. {
  205. if(self && self->main_loop == NULL){
  206. //DEBUG("init_main_loop");
  207. //DEBUG("self %p" ,self);
  208. picoev_init(self->maxfd);
  209. self->main_loop = picoev_create_loop(60);
  210. self->main_loop->now = time(NULL);
  211. }
  212. }
  213. static void
  214. destroy_main_loop(HubObject *self)
  215. {
  216. if(self && self->main_loop != NULL){
  217. DEBUG("self %p" ,self);
  218. picoev_destroy_loop(self->main_loop);
  219. picoev_deinit();
  220. self->main_loop = NULL;
  221. }
  222. }
  223. void
  224. reset_main_loop(void)
  225. {
  226. HubObject *hub = internal_get_hub();
  227. if(hub != NULL){
  228. destroy_main_loop(hub);
  229. init_main_loop(hub);
  230. }
  231. }
  232. static int
  233. internal_loop(HubObject *self)
  234. {
  235. int ret = 1;
  236. heapq_t *q = g_timers;
  237. picoev_loop *loop = NULL;
  238. init_main_loop(self);
  239. if(suspend_thread){
  240. //reset_main_loop();
  241. DEBUG("switch to suspend_thread");
  242. PyObject *o = greenlet_switch(suspend_thread, NULL, NULL);
  243. Py_XDECREF(o);
  244. Py_DECREF(suspend_thread);
  245. suspend_thread = NULL;
  246. }
  247. loop_done = 1;
  248. DEBUG("loop start loop:%p activecnt:%d", self->main_loop, activecnt);
  249. loop = self->main_loop;
  250. while (likely(loop_done && activecnt > 0)) {
  251. if(unlikely(fire_pendings() == -1)){
  252. //error stop hub
  253. loop_done = 0;
  254. RDEBUG("loop_done = 0");
  255. ret = -1;
  256. continue;
  257. }
  258. if(q->size > 0){
  259. if(unlikely(fire_timer() == -1)){
  260. loop_done = 0;
  261. RDEBUG("loop_done = 0");
  262. ret = -1;
  263. continue;
  264. }
  265. }
  266. if(ioactivecnt > 0 || q->size > 0){
  267. picoev_loop_once(loop, 10);
  268. }
  269. //DEBUG("%d", main_loop->timeout.resolution);
  270. /*
  271. if(watchdog){
  272. //check
  273. watchdog_result = PyObject_CallFunction(watchdog, NULL);
  274. if(PyErr_Occurred()){
  275. PyErr_Print();
  276. //PyErr_Clear();
  277. }
  278. Py_XDECREF(watchdog_result);
  279. }*/
  280. //DEBUG("active event io:%d/total:%d", ioactivecnt, activecnt);
  281. }
  282. //abort ??
  283. if(PyErr_Occurred()){
  284. //if(stopped || PyErr_Occurred()){
  285. ret = -1;
  286. }
  287. //destroy_main_loop(self);
  288. //reset_main_loop();
  289. //TODO clear timer queure and pendings
  290. //activecnt -= ioactivecnt;
  291. //ioactivecnt = 0;
  292. RDEBUG("loop end ret:%d", ret);
  293. DEBUG("fin active event io:%d/total:%d", ioactivecnt, activecnt);
  294. stopped = 0;
  295. loop_done= 0;
  296. return ret;
  297. }
  298. static void
  299. switch_user_thread(picoev_loop* loop, int fd, PyGreenlet *greenlet)
  300. {
  301. PyObject *res = NULL;
  302. RDEBUG("del event fd:%d thread:%p", fd, greenlet);
  303. //clear event
  304. picoev_del(loop, fd);
  305. activecnt--;
  306. ioactivecnt--;
  307. if(!PyErr_Occurred()){
  308. res = greenlet_switch(greenlet, NULL, NULL);
  309. Py_XDECREF(res);
  310. }else{
  311. loop_done = 0;
  312. }
  313. }
  314. static inline HubObject*
  315. internal_get_hub(void)
  316. {
  317. HubObject *self;
  318. static HubObject *g_hub = NULL;
  319. if(g_hub != NULL){
  320. return g_hub;
  321. }
  322. self = PyObject_NEW(HubObject, &HubObjectType);
  323. if(self == NULL){
  324. return NULL;
  325. }
  326. self->main_loop = NULL;
  327. self->greenlet = NULL;
  328. self->maxfd = 1024;
  329. //DEBUG("self %p", self);
  330. if(internal_init_hub_thread(self) == -1){
  331. PyObject_DEL(self);
  332. return NULL;
  333. }
  334. g_hub = self;
  335. return g_hub;
  336. }
  337. PyObject *
  338. get_hub(void)
  339. {
  340. return (PyObject*)internal_get_hub();
  341. }
  342. static void
  343. HubObject_dealloc(HubObject *self)
  344. {
  345. DEBUG("self %p", self);
  346. Py_XDECREF(self->greenlet);
  347. PyObject_DEL(self);
  348. }
  349. static PyObject*
  350. HubObject_run(HubObject *self, PyObject *args)
  351. {
  352. PyObject *ret;
  353. DEBUG("self %p", self);
  354. while(1){
  355. if(loop_done == 1){
  356. DEBUG("already running");
  357. Py_RETURN_NONE;
  358. }
  359. if(internal_loop(self) < 0){
  360. return NULL;
  361. }
  362. if(catch_signal){
  363. //override
  364. PyErr_Clear();
  365. PyErr_SetNone(PyExc_KeyboardInterrupt);
  366. catch_signal = 0;
  367. return NULL;
  368. }
  369. RDEBUG("hub stopped loop_done:%d", loop_done);
  370. PyErr_SetString(HubAbortException, "loop block forever");
  371. ret = greenlet_throw_err(PyGreenlet_GET_PARENT(self->greenlet));
  372. Py_XDECREF(ret);
  373. }
  374. Py_RETURN_NONE;
  375. }
  376. PyObject*
  377. hub_abort(void)
  378. {
  379. HubObject *self = internal_get_hub();
  380. DEBUG("self %p", self);
  381. if(loop_done == 1){
  382. stopped = 1;
  383. loop_done = 0;
  384. RDEBUG("loop_done = 0");
  385. if(PyGreenlet_STARTED(self->greenlet)){
  386. //if(!PyErr_Occurred()){
  387. //PyErr_SetString(PyExc_IOError, "hub aborted");
  388. //}
  389. return hub_switch();
  390. }
  391. }
  392. Py_RETURN_NONE;
  393. }
  394. static PyObject*
  395. HubObject_abort(HubObject *self, PyObject *args)
  396. {
  397. DEBUG("self %p", self);
  398. return hub_abort();
  399. }
  400. static PyObject*
  401. HubObject_reset(HubObject *self, PyObject *args)
  402. {
  403. DEBUG("self %p", self);
  404. if(stopped == 1){
  405. loop_done = 1;
  406. stopped = 0;
  407. }
  408. Py_RETURN_NONE;
  409. }
  410. static int
  411. internal_init_hub_thread(HubObject *self)
  412. {
  413. PyObject *run;
  414. PyGreenlet *temp;
  415. Py_CLEAR(self->greenlet);
  416. run = PyObject_GetAttrString((PyObject *)self, "run");
  417. if(run == NULL){
  418. return -1;
  419. }
  420. temp = greenlet_new(run, NULL);
  421. if(temp == NULL){
  422. return -1;
  423. }
  424. Py_DECREF(run);
  425. Py_INCREF(temp);
  426. self->greenlet = temp;
  427. //DEBUG("create new hub greenlet %p", temp);
  428. return 1;
  429. }
  430. int
  431. init_hub_thread(void)
  432. {
  433. return internal_init_hub_thread(internal_get_hub());
  434. }
  435. PyObject*
  436. hub_switch(void)
  437. {
  438. PyGreenlet *current = NULL, *parent = NULL;
  439. HubObject *self = internal_get_hub();
  440. current = greenlet_getcurrent();
  441. if(self->greenlet == current){
  442. parent = PyGreenlet_GET_PARENT(self->greenlet);
  443. Py_DECREF(current);
  444. return greenlet_switch(parent, NULL, NULL);
  445. }
  446. DEBUG("switch hub:%p hub_parent:%p current:%p", self->greenlet, PyGreenlet_GET_PARENT(self->greenlet), current);
  447. if(!stopped){
  448. //dead check
  449. if(greenlet_dead(self->greenlet)){
  450. //PyErr_SetString(PyExc_IOError, "stoped hub thread");
  451. DEBUG("warning !! hub is dead");
  452. if(internal_init_hub_thread(self) < 0){
  453. Py_DECREF(current);
  454. return NULL;
  455. }
  456. }
  457. parent = PyGreenlet_GET_PARENT(self->greenlet);
  458. if(parent != current){
  459. greenlet_setparent(current, self->greenlet);
  460. }
  461. }
  462. Py_DECREF(current);
  463. return greenlet_switch(self->greenlet, NULL, NULL);
  464. }
  465. static PyObject*
  466. HubObject_switch(HubObject *self, PyObject *args)
  467. {
  468. return hub_switch();
  469. }
  470. static PyObject*
  471. HubObject_join(HubObject *self, PyObject *args, PyObject *kwargs)
  472. {
  473. PyObject *ret;
  474. ret = hub_switch();
  475. if(PyErr_ExceptionMatches(HubAbortException)){
  476. DEBUG("hub abort");
  477. PyErr_Clear();
  478. Py_XDECREF(ret);
  479. Py_RETURN_NONE;
  480. }
  481. return ret;
  482. }
  483. PyObject*
  484. spawn(PyObject *callable, PyObject *args)
  485. {
  486. PyObject *ret;
  487. PyGreenlet *greenlet;
  488. HubObject *hub;
  489. hub = internal_get_hub();
  490. greenlet = greenlet_new(callable, hub->greenlet);
  491. if(greenlet == NULL){
  492. return NULL;
  493. }
  494. DEBUG("start thread:%p cnt:%d", greenlet, (int)Py_REFCNT(greenlet));
  495. ret = greenlet_switch(greenlet, args, NULL);
  496. Py_DECREF(greenlet);
  497. DEBUG("fin thread:%p ret:%p cnt:%d", greenlet, ret, (int)Py_REFCNT(greenlet));
  498. return ret;
  499. }
  500. static void
  501. print_exception(PyObject *context, PyObject *type, PyObject *value, PyObject *traceback)
  502. {
  503. if(PyObject_IsSubclass(type, system_errors)){
  504. DEBUG("ignore");
  505. return;
  506. }
  507. if(traceback == NULL){
  508. traceback = Py_None;
  509. }
  510. Py_INCREF(type);
  511. Py_INCREF(value);
  512. Py_INCREF(traceback);
  513. PyErr_Restore(type, value, traceback);
  514. PyErr_Print();
  515. if(context != NULL){
  516. PySys_WriteStderr("%s occured from ", PyExceptionClass_Name(type));
  517. PyObject_Print(context, stderr, 0);
  518. PySys_WriteStderr(" \n");
  519. }
  520. return ;
  521. }
  522. PyObject*
  523. internal_hub_handle_error(PyObject *type, PyObject *value, PyObject *traceback, int checktype)
  524. {
  525. PyGreenlet *current, *parent;
  526. PyObject *o, *throw, *timer;
  527. HubObject *hub = internal_get_hub();
  528. if(checktype && !PyObject_IsSubclass(type, system_errors)){
  529. DEBUG("ignore exception");
  530. Py_RETURN_NONE;
  531. }
  532. current = greenlet_getcurrent();
  533. parent = PyGreenlet_GET_PARENT(hub->greenlet);
  534. RDEBUG("hub->greenlet:%p current:%p parent:%p", hub->greenlet, current, parent);
  535. if(current == hub->greenlet || current == parent){
  536. Py_DECREF(current);
  537. return greenlet_throw(parent, type, value, traceback);
  538. }else{
  539. Py_DECREF(current);
  540. o = Py_BuildValue("OOO", type, value, traceback);
  541. if(o == NULL){
  542. return NULL;
  543. }
  544. throw = PyObject_GetAttrString((PyObject*)parent, "throw");
  545. if(throw == NULL){
  546. return NULL;
  547. }
  548. timer = internal_hub_schedule_call(0, throw, o, NULL, NULL);
  549. if(timer == NULL){
  550. Py_DECREF(timer);
  551. return NULL;
  552. }
  553. Py_DECREF(throw);
  554. Py_DECREF(timer);
  555. Py_RETURN_NONE;
  556. }
  557. }
  558. PyObject*
  559. hub_handle_error(PyObject *context, PyObject *type, PyObject *value, PyObject *traceback)
  560. {
  561. PyObject *t = type, *v = value, *tr = traceback;
  562. DEBUG("context:%p type:%p value:%p traceback:%p", context, type, value, traceback);
  563. if(t == NULL && v == NULL){
  564. PyErr_Fetch(&t, &v, &tr);
  565. PyErr_Clear();
  566. if(tr == NULL){
  567. tr = Py_None;
  568. Py_INCREF(tr);
  569. }
  570. }
  571. print_exception(context, type, value, traceback);
  572. return internal_hub_handle_error(t, v, tr, 1);
  573. }
  574. static PyObject*
  575. hub_handle_timeout_error(PyObject *context)
  576. {
  577. PyObject *t, *v, *tr;
  578. PyErr_Fetch(&t, &v, &tr);
  579. PyErr_Clear();
  580. if(tr == NULL){
  581. tr = Py_None;
  582. Py_INCREF(tr);
  583. }
  584. print_exception(context, t, v, tr);
  585. return internal_hub_handle_error(t, v, tr, 0);
  586. }
  587. static inline PyObject*
  588. internal_hub_schedule_call(int seconds, PyObject *cb, PyObject *args, PyObject *kwargs, PyGreenlet *greenlet)
  589. {
  590. TimerObject *timer;
  591. pending_queue_t *pendings = g_pendings;
  592. heapq_t *timers = g_timers;
  593. timer = TimerObject_new(seconds, cb, greenlet, args, kwargs);
  594. if(timer == NULL){
  595. return NULL;
  596. }
  597. if(!seconds){
  598. if(realloc_pendings() == -1){
  599. Py_DECREF(timer);
  600. return NULL;
  601. }
  602. Py_INCREF(timer);
  603. //timer->pending = ++pendings->size;
  604. pendings->q[pendings->size] = timer;
  605. pendings->size++;
  606. DEBUG("add timer:%p pendings->size:%d", timer, pendings->size);
  607. }else{
  608. if(heappush(timers, timer) == -1){
  609. Py_DECREF(timer);
  610. return NULL;
  611. }
  612. }
  613. activecnt++;
  614. return (PyObject *)timer;
  615. }
  616. PyObject*
  617. hub_schedule_call(int seconds, PyObject *cb, PyObject *args, PyObject *kwargs, PyGreenlet *greenlet)
  618. {
  619. return internal_hub_schedule_call(seconds, cb, args, kwargs, greenlet);
  620. }
  621. PyObject*
  622. hub_set_timeout(int seconds, PyObject *exception)
  623. {
  624. TimerObject *timer;
  625. PyGreenlet *greenlet;
  626. PyObject *o, *throw, *exc, *value;
  627. exc = exception;
  628. if(exc == NULL){
  629. exc = TimeoutException;
  630. }
  631. value = PyObject_CallFunction(exc, "", NULL);
  632. o = Py_BuildValue("OOO", exc, value, Py_None);
  633. if(o == NULL){
  634. return NULL;
  635. }
  636. greenlet = greenlet_getcurrent();
  637. throw = PyObject_GetAttrString((PyObject*)greenlet, "throw");
  638. if(throw == NULL){
  639. return NULL;
  640. }
  641. timer = (TimerObject*)internal_hub_schedule_call(seconds, throw, o, NULL, NULL);
  642. Py_DECREF(o);
  643. Py_DECREF(throw);
  644. Py_DECREF(greenlet);
  645. if(exc == TimeoutException && (PyObject_SetAttrString(value, "timer", (PyObject*)timer) == -1)){
  646. timer->called = 1;
  647. Py_DECREF(timer);
  648. return NULL;
  649. }
  650. return (PyObject *)timer;
  651. }
  652. static PyObject*
  653. internal_schedule_call(HubObject *self, PyObject *args, PyObject *kwargs, PyGreenlet *greenlet)
  654. {
  655. long seconds = 0, ret;
  656. Py_ssize_t size;
  657. PyObject *sec = NULL, *cb = NULL, *cbargs = NULL, *timer;
  658. DEBUG("self %p", self);
  659. size = PyTuple_GET_SIZE(args);
  660. DEBUG("args size %d", (int)size);
  661. if(size < 2){
  662. PyErr_SetString(PyExc_TypeError, "schedule_call takes exactly 2 argument");
  663. return NULL;
  664. }
  665. sec = PyTuple_GET_ITEM(args, 0);
  666. cb = PyTuple_GET_ITEM(args, 1);
  667. #ifdef PY3
  668. if(!PyLong_Check(sec)){
  669. #else
  670. if(!PyInt_Check(sec)){
  671. #endif
  672. PyErr_SetString(PyExc_TypeError, "must be integer");
  673. return NULL;
  674. }
  675. if(!PyCallable_Check(cb)){
  676. PyErr_SetString(PyExc_TypeError, "must be callable");
  677. return NULL;
  678. }
  679. ret = PyLong_AsLong(sec);
  680. if(PyErr_Occurred()){
  681. return NULL;
  682. }
  683. if(ret < 0){
  684. PyErr_SetString(PyExc_TypeError, "seconds value out of range");
  685. return NULL;
  686. }
  687. seconds = ret;
  688. if(size > 2){
  689. cbargs = PyTuple_GetSlice(args, 2, size);
  690. }
  691. timer = internal_hub_schedule_call(seconds, cb, cbargs, kwargs, greenlet);
  692. Py_XDECREF(cbargs);
  693. return timer;
  694. }
  695. static PyObject*
  696. HubObject_schedule_call_local(HubObject *self, PyObject *args, PyObject *kwargs)
  697. {
  698. //DEBUG("HubObject_schedule_call_local self %p", self);
  699. PyObject *ret = NULL;
  700. PyGreenlet *temp = greenlet_getcurrent();
  701. if(temp == NULL){
  702. return NULL;
  703. }
  704. //DEBUG("schedule_call current greenlet:%p self:%p", temp, self->greenlet);
  705. if(temp == self->greenlet){
  706. DEBUG("global self %p", self);
  707. ret = internal_schedule_call(self, args, kwargs, NULL);
  708. }else{
  709. DEBUG("local self %p", self);
  710. ret = internal_schedule_call(self, args, kwargs, temp);
  711. }
  712. Py_DECREF(temp);
  713. return ret;
  714. }
  715. static PyObject*
  716. HubObject_schedule_call_global(HubObject *self, PyObject *args, PyObject *kwargs)
  717. {
  718. DEBUG("self %p", self);
  719. return internal_schedule_call(self, args, kwargs, NULL);
  720. }
  721. static void
  722. trampoline_switch_callback(picoev_loop* loop, int fd, int events, void* cb_arg)
  723. {
  724. switch_arg_t *switch_arg = NULL;
  725. PyObject *res = NULL;
  726. switch_arg = (switch_arg_t*)cb_arg;
  727. DEBUG("trampoline_switch_callback loop:%p thread:%p fd:%d events:%d ", loop, switch_arg->greenlet, fd, events);
  728. if ((events & PICOEV_TIMEOUT) != 0) {
  729. DEBUG("trampoline_switch_callback timeout !!!!");
  730. PyErr_SetString(switch_arg->timeout_exc, "timeout");
  731. res = hub_handle_timeout_error((PyObject*)switch_arg->greenlet);
  732. } else if ((events & PICOEV_WRITE) != 0 || (events & PICOEV_READ) != 0) {
  733. res = greenlet_switch(switch_arg->greenlet, NULL, NULL);
  734. }
  735. Py_XDECREF(res);
  736. }
  737. static int
  738. ready_trampoline(HubObject *hub, int loop_check)
  739. {
  740. PyObject *o = NULL;
  741. PyGreenlet *current = NULL;
  742. if(hub->main_loop == NULL || greenlet_dead(hub->greenlet)){
  743. RDEBUG("hub not running !!!! hub:%p loop_done:%d hub->main_loop:%p", hub, loop_done, hub->main_loop);
  744. suspend_thread = greenlet_getcurrent();
  745. o = hub_switch();
  746. Py_XDECREF(o);
  747. return 1;
  748. }
  749. if(loop_check){
  750. current = greenlet_getcurrent();
  751. if(current == hub->greenlet){
  752. RDEBUG("Cannot switch to MAINLOOP from MAINLOOP");
  753. PyErr_SetString(PyExc_IOError, "Cannot switch to MAINLOOP from MAINLOOP");
  754. Py_DECREF(current);
  755. return -1;
  756. }
  757. Py_DECREF(current);
  758. }
  759. return 1;
  760. }
  761. static inline PyObject*
  762. internal_io_trampoline(HubObject *hub, int fd, int event, int timeout, PyObject *exception, PyObject *args)
  763. {
  764. int ret, active;
  765. int t = timeout < 0 ? 0 : timeout;
  766. switch_arg_t *switch_arg;
  767. PyGreenlet *current = NULL;
  768. PyObject *res;
  769. //TODO check exception type
  770. switch_arg = PyMem_Malloc(sizeof(switch_arg_t));
  771. if(switch_arg == NULL){
  772. return NULL;
  773. }
  774. memset(switch_arg, 0, sizeof(switch_arg_t));
  775. current = greenlet_getcurrent();
  776. DEBUG("thread:%p cnt:%d", current, (int)Py_REFCNT(current));
  777. // switch to hub
  778. RDEBUG("add event loop:%p thread:%p fd:%d event:%d timeout:%d", hub->main_loop, current, fd, event, t);
  779. switch_arg->greenlet = current;
  780. switch_arg->timeout_exc = exception != NULL ? exception : TimeoutException;
  781. active = picoev_is_active(hub->main_loop, fd);
  782. ret = picoev_add(hub->main_loop, fd, event, t, trampoline_switch_callback, (void *)switch_arg);
  783. if((ret == 0 && !active)){
  784. activecnt++;
  785. ioactivecnt++;
  786. }
  787. res = greenlet_switch(hub->greenlet, args, NULL);
  788. PyMem_Free(switch_arg);
  789. Py_DECREF(current);
  790. RDEBUG("del event fd:%d thread:%p", fd, current);
  791. //clear event
  792. picoev_del(hub->main_loop, fd);
  793. activecnt--;
  794. ioactivecnt--;
  795. return res;
  796. }
  797. int
  798. io_trampoline(int fd, int event, int timeout, PyObject *exception)
  799. {
  800. HubObject *hub = internal_get_hub();
  801. DEBUG("fd:%d event:%d timeout:%d exception:%p", fd, event, timeout, exception);
  802. if(ready_trampoline(hub, 1) < 0){
  803. return -1;
  804. }
  805. PyObject *ret = internal_io_trampoline(hub, fd, event, timeout, exception, NULL);
  806. Py_XDECREF(ret);
  807. if(ret == NULL && PyErr_Occurred()){
  808. //PyErr_Print();
  809. RDEBUG("io_trampoline exception !!!!");
  810. //error
  811. return -1;
  812. }
  813. return 1;
  814. }
  815. static PyObject*
  816. HubObject_trampoline(HubObject *self, PyObject *args, PyObject *kwargs)
  817. {
  818. int fd, event, timeout = 0;
  819. PyObject *read = Py_None, *write = Py_None;
  820. HubObject *hub = NULL;
  821. static char *keywords[] = {"fileno", "read", "write", "timeout", NULL};
  822. if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|OOi:trampoline", keywords, &fd, &read, &write, &timeout)){
  823. return NULL;
  824. }
  825. if(fd < 0){
  826. PyErr_SetString(PyExc_ValueError, "fileno value out of range ");
  827. return NULL;
  828. }
  829. if(timeout < 0){
  830. PyErr_SetString(PyExc_ValueError, "timeout value out of range ");
  831. return NULL;
  832. }
  833. if(PyObject_IsTrue(read) && PyObject_IsTrue(write)){
  834. event = PICOEV_READWRITE;
  835. }else if(PyObject_IsTrue(read)){
  836. event = PICOEV_READ;
  837. }else if(PyObject_IsTrue(write)){
  838. event = PICOEV_WRITE;
  839. }else{
  840. event = PICOEV_TIMEOUT;
  841. if(timeout <= 0){
  842. PyErr_SetString(PyExc_ValueError, "timeout value out of range ");
  843. return NULL;
  844. }
  845. }
  846. hub = internal_get_hub();
  847. if(ready_trampoline(hub, 1) < 0){
  848. return NULL;
  849. }
  850. //TODO set exception
  851. return internal_io_trampoline(hub, fd, event, timeout, NULL, NULL);
  852. }
  853. void
  854. switch_callback(picoev_loop* loop, int fd, int events, void* cb_arg)
  855. {
  856. PyGreenlet *t = (PyGreenlet *)cb_arg;
  857. PyObject *res, *args;
  858. DEBUG("thread:%p fd:%d events:%d",t, fd, events);
  859. args = Py_BuildValue("(i)", fd);
  860. res = PyGreenlet_Switch(t, args, NULL);
  861. Py_XDECREF(res);
  862. }
  863. int
  864. add_switch_event(int fd, int event, int timeout, picoev_handler *cb)
  865. {
  866. int ret, active;
  867. HubObject *hub = internal_get_hub();
  868. PyGreenlet *current = NULL;
  869. if(ready_trampoline(hub, 1) < 0){
  870. return -1;
  871. }
  872. current = greenlet_getcurrent();
  873. // switch to hub
  874. RDEBUG("add event loop:%p thread:%p fd:%d event:%d timeout:%d", hub->main_loop, current, fd, event, timeout);
  875. active = picoev_is_active(hub->main_loop, fd);
  876. ret = picoev_add(hub->main_loop, fd, event, timeout, cb, (void *)current);
  877. if(ret == 0 && !active){
  878. activecnt++;
  879. ioactivecnt++;
  880. }
  881. Py_DECREF(current);
  882. return 1;
  883. }
  884. int
  885. add_event(int fd, int event, int timeout, picoev_handler *cb, void *data)
  886. {
  887. int ret, active;
  888. HubObject *hub = internal_get_hub();
  889. if(ready_trampoline(hub, 0) < 0){
  890. return -1;
  891. }
  892. // switch to hub
  893. RDEBUG("add event loop:%p fd:%d event:%d timeout:%d", hub->main_loop, fd, event, timeout);
  894. active = picoev_is_active(hub->main_loop, fd);
  895. ret = picoev_add(hub->main_loop, fd, event, timeout, cb, (void *)data);
  896. if(ret == 0 && !active){
  897. activecnt++;
  898. ioactivecnt++;
  899. }
  900. return 1;
  901. }
  902. int
  903. is_active_event(int fd)
  904. {
  905. HubObject *hub = internal_get_hub();
  906. if(hub && hub->main_loop){
  907. return picoev_is_active(hub->main_loop, fd);
  908. }
  909. return 0;
  910. }
  911. void
  912. del_event(int fd)
  913. {
  914. HubObject *hub = internal_get_hub();
  915. if(hub->main_loop && picoev_is_active(hub->main_loop, fd)){
  916. RDEBUG("del event fd:%d", fd);
  917. picoev_del(hub->main_loop, fd);
  918. activecnt--;
  919. ioactivecnt--;
  920. }
  921. }
  922. void
  923. update_event_timeout(int fd, int timeout)
  924. {
  925. HubObject *hub = internal_get_hub();
  926. picoev_set_timeout(hub->main_loop, fd, timeout);
  927. }
  928. int
  929. cmp_hub_thread(PyGreenlet *greenlet)
  930. {
  931. HubObject *hub;
  932. hub = (HubObject*)get_hub();
  933. if(hub->greenlet == NULL){
  934. return 0;
  935. }
  936. return hub->greenlet == greenlet;
  937. }
  938. static PyObject*
  939. HubObject_sleep_callback(PyObject *self, PyObject *args)
  940. {
  941. PyObject *o, *ret;
  942. o = PyTuple_GET_ITEM(args, 0);
  943. if(o == NULL){
  944. return NULL;
  945. }
  946. ret = greenlet_switch((PyGreenlet*)o, NULL, NULL);
  947. Py_XDECREF(ret);
  948. Py_RETURN_NONE;
  949. }
  950. int
  951. time_sleep(int time)
  952. {
  953. PyObject *args, *timer, *ret;
  954. PyGreenlet *current;
  955. current = greenlet_getcurrent();
  956. if(current == NULL){
  957. return -1;
  958. }
  959. args = Py_BuildValue("(O)", current);
  960. if(args == NULL){
  961. Py_DECREF(current);
  962. return -1;
  963. }
  964. timer = internal_hub_schedule_call(time, sleep_callback, args, NULL, NULL);
  965. Py_DECREF(current);
  966. Py_DECREF(args);
  967. if(timer == NULL){
  968. return -1;
  969. }
  970. Py_DECREF(timer);
  971. ret = hub_switch();
  972. Py_XDECREF(ret);
  973. return 1;
  974. }
  975. static PyMethodDef HubObject_methods[] = {
  976. {"run", (PyCFunction)HubObject_run, METH_NOARGS, 0},
  977. {"join", (PyCFunction)HubObject_join, METH_VARARGS|METH_KEYWORDS, 0},
  978. {"schedule_call", (PyCFunction)HubObject_schedule_call_local, METH_VARARGS|METH_KEYWORDS, 0},
  979. {"schedule_call_local", (PyCFunction)HubObject_schedule_call_local, METH_VARARGS|METH_KEYWORDS, 0},
  980. {"schedule_call_global", (PyCFunction)HubObject_schedule_call_global, METH_VARARGS|METH_KEYWORDS, 0},
  981. {"trampoline", (PyCFunction)HubObject_trampoline, METH_VARARGS|METH_KEYWORDS, 0},
  982. {NULL, NULL}
  983. };
  984. static PyMemberDef HubObject_members[] = {
  985. {"greenlet", T_OBJECT_EX, offsetof(HubObject, greenlet), READONLY, "hub greenlet"},
  986. {NULL} /* Sentinel */
  987. };
  988. PyTypeObject HubObjectType = {
  989. #ifdef PY3
  990. PyVarObject_HEAD_INIT(NULL, 0)
  991. #else
  992. PyObject_HEAD_INIT(NULL)
  993. 0, /* ob_size */
  994. #endif
  995. MODULE_NAME ".Hub", /*tp_name*/
  996. sizeof(HubObject), /*tp_basicsize*/
  997. 0, /*tp_itemsize*/
  998. (destructor)HubObject_dealloc, /*tp_dealloc*/
  999. 0, /*tp_print*/
  1000. 0, /*tp_getattr*/
  1001. 0, /*tp_setattr*/
  1002. 0, /*tp_compare*/
  1003. 0, /*tp_repr*/
  1004. 0, /*tp_as_number*/
  1005. 0, /*tp_as_sequence*/
  1006. 0, /*tp_as_mapping*/
  1007. 0, /*tp_hash */
  1008. 0, /*tp_call*/
  1009. 0, /*tp_str*/
  1010. 0, /*tp_getattro*/
  1011. 0, /*tp_setattro*/
  1012. 0, /*tp_as_buffer*/
  1013. Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/
  1014. "Hub", /* tp_doc */
  1015. 0, /* tp_traverse */
  1016. 0, /* tp_clear */
  1017. 0, /* tp_richcompare */
  1018. 0, /* tp_weaklistoffset */
  1019. 0, /* tp_iter */
  1020. 0, /* tp_iternext */
  1021. HubObject_methods, /* tp_methods */
  1022. HubObject_members, /* tp_members */
  1023. 0, /* tp_getset */
  1024. 0, /* tp_base */
  1025. 0, /* tp_dict */
  1026. 0, /* tp_descr_get */
  1027. 0, /* tp_descr_set */
  1028. 0, /* tp_dictoffset */
  1029. 0, /* tp_init */
  1030. 0, /* tp_alloc */
  1031. 0, /* tp_new */
  1032. };
  1033. static PyMethodDef sleep_callback_def = {"_callback", (PyCFunction)HubObject_sleep_callback, METH_VARARGS, 0};
  1034. int
  1035. init_hub_module(void)
  1036. {
  1037. int ret;
  1038. //DEBUG("init_hub_module");
  1039. //TODO Check alloc error, free, etc.
  1040. system_errors = Py_BuildValue("OOOO", PyExc_KeyboardInterrupt, PyExc_SystemExit, PyExc_SystemError, PyExc_AssertionError);
  1041. if(system_errors == NULL){
  1042. return -1;
  1043. }
  1044. g_timers = init_queue();
  1045. if(g_timers == NULL){
  1046. return -1;
  1047. }
  1048. ret = init_pendings();
  1049. if(ret == -1){
  1050. return -1;
  1051. }
  1052. PyOS_setsig(SIGPIPE, sigpipe_cb);
  1053. PyOS_setsig(SIGINT, sigint_cb);
  1054. PyOS_setsig(SIGTERM, sigint_cb);
  1055. if(get_hub() == NULL){
  1056. return -1;
  1057. }
  1058. /*
  1059. DEBUG("TimerObject size %d", sizeof(TimerObject));
  1060. DEBUG("buffer size %d", sizeof(buffer));
  1061. DEBUG("Socket size %d", sizeof(SocketObject));
  1062. DEBUG("pending_queue_t size %d", sizeof(pending_queue_t));
  1063. */
  1064. sleep_callback = PyCFunction_NewEx(&sleep_callback_def, (PyObject *)NULL, NULL);
  1065. return 1;
  1066. }