| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158 | /*  +----------------------------------------------------------------------+  | PHP Version 5                                                        |  +----------------------------------------------------------------------+  | Copyright (c) 1997-2013 The PHP Group                                |  +----------------------------------------------------------------------+  | http://www.opensource.org/licenses/mit-license.php  MIT License      |  +----------------------------------------------------------------------+  | Author: Jani Taskinen <[email protected]>                         |  | Author: Patrick Reilly <[email protected]>                             |  +----------------------------------------------------------------------+*/#ifdef HAVE_CONFIG_H#include "config.h"#endif#ifdef _WIN32#include <concrt.h>#endif#include "php_v8js_macros.h"#include "v8js_v8.h"#include "v8js_exceptions.h"#include "v8js_timer.h"extern "C" {#include "ext/date/php_date.h"#include "ext/standard/php_string.h"#include "zend_interfaces.h"#include "zend_closures.h"#include "ext/spl/spl_exceptions.h"#include "zend_exceptions.h"}static void v8js_timer_interrupt_handler(v8::Isolate *isolate, void *data) { /* {{{ */	zend_v8js_globals *globals = static_cast<zend_v8js_globals *>(data);	if (!globals->timer_stack.size()) {		return;	}	v8::Locker locker(isolate);	v8::HeapStatistics hs;	bool send_notification = false;	bool has_sent_notification = false;	do {		if (send_notification) {			isolate->LowMemoryNotification();			has_sent_notification = true;		}		isolate->GetHeapStatistics(&hs);		globals->timer_mutex.lock();		for (std::deque< v8js_timer_ctx* >::iterator it = globals->timer_stack.begin();			 it != globals->timer_stack.end(); it ++) {			v8js_timer_ctx *timer_ctx = *it;			v8js_ctx *c = timer_ctx->ctx;			if(c->isolate != isolate || timer_ctx->killed) {				continue;			}			if (timer_ctx->memory_limit > 0 && hs.used_heap_size() > timer_ctx->memory_limit) {				if (has_sent_notification) {					timer_ctx->killed = true;					v8::V8::TerminateExecution(c->isolate);					c->memory_limit_hit = true;				} else {					// force garbage collection, then check again					send_notification = true;					break;				}			}		}		globals->timer_mutex.unlock();	} while(send_notification != has_sent_notification);}/* }}} */void v8js_timer_thread(zend_v8js_globals *globals) /* {{{ */{	while (!globals->timer_stop) {		globals->timer_mutex.lock();		if (globals->timer_stack.size()) {			v8js_timer_ctx *timer_ctx = globals->timer_stack.front();			v8js_ctx *c = timer_ctx->ctx;			std::chrono::time_point<std::chrono::high_resolution_clock> now = std::chrono::high_resolution_clock::now();			if(timer_ctx->killed) {				/* execution already terminated, nothing to check anymore,				 * but wait for caller to pop this timer context. */			}			else if(timer_ctx->time_limit > 0 && now > timer_ctx->time_point) {				timer_ctx->killed = true;				v8::V8::TerminateExecution(c->isolate);				c->time_limit_hit = true;			}			else if (timer_ctx->memory_limit > 0) {				/* If a memory_limit is set, we need to interrupt execution				 * and check heap size within the callback.  We must *not*				 * directly call GetHeapStatistics here, since we don't have				 * a v8::Locker on the isolate, but are expected to hold one,				 * and cannot aquire it as v8 is executing the script ... */				c->isolate->RequestInterrupt(v8js_timer_interrupt_handler, static_cast<void *>(globals));			}		}		globals->timer_mutex.unlock();		// Sleep for 10ms#ifdef _WIN32		concurrency::wait(10);#else		std::chrono::milliseconds duration(10);		std::this_thread::sleep_for(duration);#endif	}}/* }}} */void v8js_timer_push(long time_limit, long memory_limit, v8js_ctx *c TSRMLS_DC) /* {{{ */{	V8JSG(timer_mutex).lock();	// Create context for this timer	v8js_timer_ctx *timer_ctx = (v8js_timer_ctx *)emalloc(sizeof(v8js_timer_ctx));	// Calculate the time point when the time limit is exceeded	std::chrono::milliseconds duration(time_limit);	std::chrono::time_point<std::chrono::high_resolution_clock> from = std::chrono::high_resolution_clock::now();	// Push the timer context	timer_ctx->time_limit = time_limit;	timer_ctx->memory_limit = memory_limit;	timer_ctx->time_point = from + duration;	timer_ctx->ctx = c;	timer_ctx->killed = false;	V8JSG(timer_stack).push_front(timer_ctx);	V8JSG(timer_mutex).unlock();}/* }}} *//* * Local variables: * tab-width: 4 * c-basic-offset: 4 * indent-tabs-mode: t * End: * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */
 |