Permalink
Browse files

Ok, this time here's some real Win32 system programming :)

Redesigned the timeout system using a single timeout thread and a single window,
and used a much quicker check.
  • Loading branch information...
1 parent 43d9122 commit 84eb48f0a1fd0a8be0f09ad3b77697922d2b5bfb @zsuraski zsuraski committed Jun 16, 2000
Showing with 87 additions and 45 deletions.
  1. +3 −10 Zend/zend.c
  2. +6 −14 Zend/zend_execute.c
  3. +6 −3 Zend/zend_execute.h
  4. +68 −15 Zend/zend_execute_API.c
  5. +4 −3 Zend/zend_globals.h
View
@@ -292,19 +292,13 @@ static void executor_globals_ctor(zend_executor_globals *executor_globals)
}
zend_init_rsrc_plist(ELS_C);
EG(lambda_count)=0;
-#ifdef ZEND_WIN32
- zend_create_timeout_window(ELS_C);
-#endif
}
static void executor_globals_dtor(zend_executor_globals *executor_globals)
{
zend_shutdown_constants(ELS_C);
zend_destroy_rsrc_plist(ELS_C);
-#ifdef ZEND_WIN32
- zend_destroy_timeout_window(ELS_C);
-#endif
}
@@ -372,10 +366,6 @@ int zend_startup(zend_utility_functions *utility_functions, char **extensions, i
zval_used_for_init.refcount = 1;
zval_used_for_init.type = IS_NULL;
-#ifdef ZEND_WIN32
- zend_register_timeout_wndclass();
-#endif
-
#ifdef ZTS
global_constants_table = NULL;
compiler_globals_id = ts_allocate_id(sizeof(zend_compiler_globals), (void (*)(void *)) compiler_globals_ctor, (void (*)(void *)) compiler_globals_dtor);
@@ -407,6 +397,9 @@ int zend_startup(zend_utility_functions *utility_functions, char **extensions, i
void zend_shutdown()
{
+#ifdef ZEND_WIN32
+ zend_shutdown_timeout_thread();
+#endif
#ifndef ZTS
zend_destroy_rsrc_plist();
#endif
View
@@ -65,19 +65,6 @@ static void zend_extension_statement_handler(zend_extension *extension, zend_op_
static void zend_extension_fcall_begin_handler(zend_extension *extension, zend_op_array *op_array);
static void zend_extension_fcall_end_handler(zend_extension *extension, zend_op_array *op_array);
-#ifdef ZEND_WIN32
-#define ZEND_CHECK_TIMEOUT() \
- { \
- MSG timeout_message; \
- \
- while (PeekMessage(&timeout_message, EG(timeout_window), 0, 0, PM_REMOVE)) { \
- DispatchMessage(&timeout_message); \
- } \
- }
-#else
-#define ZEND_CHECK_TIMEOUT()
-#endif
-
#define SEPARATE_ON_READ_OBJECT(obj, _type) \
if ((obj) && ((_type) == BP_VAR_R) && ((*(obj))->type == IS_OBJECT)) { \
@@ -1005,7 +992,11 @@ void execute(zend_op_array *op_array ELS_DC)
#else
while (1) {
#endif
- ZEND_CHECK_TIMEOUT();
+#ifdef ZEND_WIN32
+ if (EG(timed_out)) {
+ zend_timeout(0);
+ }
+#endif
switch(opline->opcode) {
case ZEND_ADD:
EG(binary_op) = add_function;
@@ -2374,6 +2365,7 @@ binary_assign_op_addr: {
case ZEND_NOP:
NEXT_OPCODE();
EMPTY_SWITCH_DEFAULT_CASE()
+
}
}
#if SUPPORT_INTERACTIVE
View
@@ -157,10 +157,13 @@ ZEND_API zend_bool zend_is_executing(void);
void zend_set_timeout(long seconds);
void zend_unset_timeout(void);
+void zend_timeout(int dummy);
+
#ifdef ZEND_WIN32
-void zend_register_timeout_wndclass(void);
-void zend_create_timeout_window(ELS_D);
-void zend_destroy_timeout_window(ELS_D);
+void zend_init_timeout_thread();
+void zend_shutdown_timeout_thread();
+#define WM_REGISTER_ZEND_TIMEOUT (WM_USER+1)
+#define WM_UNREGISTER_ZEND_TIMEOUT (WM_USER+2)
#endif
#define zendi_zval_copy_ctor(p) zval_copy_ctor(&(p))
@@ -37,8 +37,13 @@
ZEND_API void (*zend_execute)(zend_op_array *op_array ELS_DC);
#ifdef ZEND_WIN32
+#include <process.h>
/* true global */
static WNDCLASS wc;
+static HWND timeout_window;
+static HANDLE timeout_thread_event;
+static DWORD timeout_thread_id;
+static int timeout_thread_initialized=0;
#endif
@@ -137,6 +142,10 @@ void init_executor(CLS_D ELS_DC)
EG(ticks_count) = 0;
EG(user_error_handler) = NULL;
+
+#ifdef ZEND_WIN32
+ EG(timed_out) = 0;
+#endif
}
@@ -531,8 +540,7 @@ void execute_new_code(CLS_D)
#endif
-#if defined(HAVE_SETITIMER) || defined(ZEND_WIN32)
-static void zend_timeout(int dummy)
+void zend_timeout(int dummy)
{
ELS_FETCH();
@@ -544,7 +552,6 @@ static void zend_timeout(int dummy)
zend_error(E_ERROR, "Maximum execution time of %d second%s exceeded",
EG(timeout_seconds), EG(timeout_seconds) == 1 ? "" : "s");
}
-#endif
#ifdef ZEND_WIN32
@@ -553,18 +560,41 @@ static LRESULT CALLBACK zend_timeout_WndProc(HWND hWnd, UINT message, WPARAM wPa
switch (message) {
case WM_DESTROY:
PostQuitMessage(0);
- return 0;
- case WM_TIMER:
- zend_timeout(0);
- return 0;
+ break;
+ case WM_REGISTER_ZEND_TIMEOUT:
+ /* wParam is the thread id pointer, lParam is the timeout amount in seconds */
+ SetTimer(timeout_window, wParam, lParam*1000, NULL);
+ break;
+ case WM_UNREGISTER_ZEND_TIMEOUT:
+ /* wParam is the thread id pointer */
+ KillTimer(timeout_window, wParam);
+ break;
+ case WM_TIMER: {
+#ifdef ZTS
+ zend_executor_globals *executor_globals;
+
+ executor_globals = ts_resource_ex(executor_globals_id, &wParam);
+ if (!executor_globals) {
+ /* Thread died before receiving its timeout? */
+ break;
+ }
+#endif
+ KillTimer(timeout_window, wParam);
+ EG(timed_out) = 1;
+ }
+ break;
default:
return DefWindowProc(hWnd,message,wParam,lParam);
}
+ return 0;
}
-void zend_register_timeout_wndclass()
+
+static unsigned __stdcall timeout_thread_proc(void *pArgs)
{
+ MSG message;
+
wc.style=0;
wc.lpfnWndProc = zend_timeout_WndProc;
wc.cbClsExtra=0;
@@ -576,21 +606,38 @@ void zend_register_timeout_wndclass()
wc.lpszMenuName=NULL;
wc.lpszClassName = "Zend Timeout Window";
if(!RegisterClass(&wc)) {
- return;
+ return -1;
+ }
+ timeout_window = CreateWindow(wc.lpszClassName, wc.lpszClassName, 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, NULL);
+ SetEvent(timeout_thread_event);
+ while (GetMessage(&message, NULL, 0, 0)) {
+ SendMessage(timeout_window, message.message, message.wParam, message.lParam);
+ if (message.message == WM_QUIT) {
+ break;
+ }
}
+ DestroyWindow(timeout_window);
+ UnregisterClass(wc.lpszClassName, NULL);
+ return 0;
}
-void zend_create_timeout_window(ELS_D)
+void zend_init_timeout_thread()
{
- EG(timeout_window) = CreateWindow(wc.lpszClassName, wc.lpszClassName, 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, NULL);
+ timeout_thread_event = CreateEvent(NULL, FALSE, FALSE, NULL);
+ _beginthreadex(NULL, 0, timeout_thread_proc, NULL, 0, &timeout_thread_id);
+ WaitForSingleObject(timeout_thread_event, INFINITE);
}
-void zend_destroy_timeout_window(ELS_D)
+void zend_shutdown_timeout_thread()
{
- DestroyWindow(EG(timeout_window));
+ if (!timeout_thread_initialized) {
+ return;
+ }
+ PostThreadMessage(timeout_thread_id, WM_QUIT, 0, 0);
}
+
#endif
/* This one doesn't exists on QNX */
@@ -604,7 +651,13 @@ void zend_set_timeout(long seconds)
EG(timeout_seconds) = seconds;
#ifdef ZEND_WIN32
- SetTimer(EG(timeout_window), 1, seconds*1000, NULL);
+ if (timeout_thread_initialized==0 && InterlockedIncrement(&timeout_thread_initialized)==1) {
+ /* We start up this process-wide thread here and not in zend_startup(), because if Zend
+ * is initialized inside a DllMain(), you're not supposed to start threads from it.
+ */
+ zend_init_timeout_thread();
+ }
+ PostThreadMessage(timeout_thread_id, WM_REGISTER_ZEND_TIMEOUT, (WPARAM) GetCurrentThreadId(), (LPARAM) seconds);
#else
# ifdef HAVE_SETITIMER
{
@@ -626,7 +679,7 @@ void zend_unset_timeout(void)
ELS_FETCH();
#ifdef ZEND_WIN32
- KillTimer(EG(timeout_window), 1);
+ PostThreadMessage(timeout_thread_id, WM_UNREGISTER_ZEND_TIMEOUT, (WPARAM) GetCurrentThreadId(), (LPARAM) 0);
#else
# ifdef HAVE_SETITIMER
{
View
@@ -167,6 +167,10 @@ struct _zend_executor_globals {
/* for extended information support */
zend_bool no_extensions;
+#ifdef ZEND_WIN32
+ zend_bool timed_out;
+#endif
+
HashTable regular_list;
HashTable persistent_list;
@@ -182,9 +186,6 @@ struct _zend_executor_globals {
/* timeout support */
int timeout_seconds;
-#ifdef ZEND_WIN32
- HWND timeout_window;
-#endif
int lambda_count;

0 comments on commit 84eb48f

Please sign in to comment.