v8js_timer.cc 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 5 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997-2013 The PHP Group |
  6. +----------------------------------------------------------------------+
  7. | http://www.opensource.org/licenses/mit-license.php MIT License |
  8. +----------------------------------------------------------------------+
  9. | Author: Jani Taskinen <[email protected]> |
  10. | Author: Patrick Reilly <[email protected]> |
  11. +----------------------------------------------------------------------+
  12. */
  13. #ifdef HAVE_CONFIG_H
  14. #include "config.h"
  15. #endif
  16. #ifdef _WIN32
  17. #include <concrt.h>
  18. #endif
  19. #include "php_v8js_macros.h"
  20. #include "v8js_v8.h"
  21. #include "v8js_exceptions.h"
  22. #include "v8js_timer.h"
  23. extern "C" {
  24. #include "ext/date/php_date.h"
  25. #include "ext/standard/php_string.h"
  26. #include "zend_interfaces.h"
  27. #include "zend_closures.h"
  28. #include "ext/spl/spl_exceptions.h"
  29. #include "zend_exceptions.h"
  30. }
  31. static void v8js_timer_interrupt_handler(v8::Isolate *isolate, void *data) { /* {{{ */
  32. zend_v8js_globals *globals = static_cast<zend_v8js_globals *>(data);
  33. if (!globals->timer_stack.size()) {
  34. return;
  35. }
  36. v8::Locker locker(isolate);
  37. v8::HeapStatistics hs;
  38. isolate->GetHeapStatistics(&hs);
  39. globals->timer_mutex.lock();
  40. for (std::deque< v8js_timer_ctx* >::iterator it = globals->timer_stack.begin();
  41. it != globals->timer_stack.end(); it ++) {
  42. v8js_timer_ctx *timer_ctx = *it;
  43. v8js_ctx *c = timer_ctx->ctx;
  44. if(c->isolate != isolate || timer_ctx->killed) {
  45. continue;
  46. }
  47. if (timer_ctx->memory_limit > 0 && hs.used_heap_size() > timer_ctx->memory_limit) {
  48. timer_ctx->killed = true;
  49. v8::V8::TerminateExecution(c->isolate);
  50. c->memory_limit_hit = true;
  51. }
  52. }
  53. globals->timer_mutex.unlock();
  54. }
  55. /* }}} */
  56. void v8js_timer_thread(zend_v8js_globals *globals) /* {{{ */
  57. {
  58. while (!globals->timer_stop) {
  59. globals->timer_mutex.lock();
  60. if (globals->timer_stack.size()) {
  61. v8js_timer_ctx *timer_ctx = globals->timer_stack.front();
  62. v8js_ctx *c = timer_ctx->ctx;
  63. std::chrono::time_point<std::chrono::high_resolution_clock> now = std::chrono::high_resolution_clock::now();
  64. if(timer_ctx->killed) {
  65. /* execution already terminated, nothing to check anymore,
  66. * but wait for caller to pop this timer context. */
  67. }
  68. else if(timer_ctx->time_limit > 0 && now > timer_ctx->time_point) {
  69. timer_ctx->killed = true;
  70. v8::V8::TerminateExecution(c->isolate);
  71. c->time_limit_hit = true;
  72. }
  73. else if (timer_ctx->memory_limit > 0) {
  74. /* If a memory_limit is set, we need to interrupt execution
  75. * and check heap size within the callback. We must *not*
  76. * directly call GetHeapStatistics here, since we don't have
  77. * a v8::Locker on the isolate, but are expected to hold one,
  78. * and cannot aquire it as v8 is executing the script ... */
  79. c->isolate->RequestInterrupt(v8js_timer_interrupt_handler, static_cast<void *>(globals));
  80. }
  81. }
  82. globals->timer_mutex.unlock();
  83. // Sleep for 10ms
  84. #ifdef _WIN32
  85. concurrency::wait(10);
  86. #else
  87. std::chrono::milliseconds duration(10);
  88. std::this_thread::sleep_for(duration);
  89. #endif
  90. }
  91. }
  92. /* }}} */
  93. void v8js_timer_push(long time_limit, long memory_limit, v8js_ctx *c TSRMLS_DC) /* {{{ */
  94. {
  95. V8JSG(timer_mutex).lock();
  96. // Create context for this timer
  97. v8js_timer_ctx *timer_ctx = (v8js_timer_ctx *)emalloc(sizeof(v8js_timer_ctx));
  98. // Calculate the time point when the time limit is exceeded
  99. std::chrono::milliseconds duration(time_limit);
  100. std::chrono::time_point<std::chrono::high_resolution_clock> from = std::chrono::high_resolution_clock::now();
  101. // Push the timer context
  102. timer_ctx->time_limit = time_limit;
  103. timer_ctx->memory_limit = memory_limit;
  104. timer_ctx->time_point = from + duration;
  105. timer_ctx->ctx = c;
  106. timer_ctx->killed = false;
  107. V8JSG(timer_stack).push_front(timer_ctx);
  108. V8JSG(timer_mutex).unlock();
  109. }
  110. /* }}} */
  111. /*
  112. * Local variables:
  113. * tab-width: 4
  114. * c-basic-offset: 4
  115. * End:
  116. * vim600: noet sw=4 ts=4 fdm=marker
  117. * vim<600: noet sw=4 ts=4
  118. */