diff options
author | Anatol Belski <ab@php.net> | 2019-02-08 18:10:31 -0800 |
---|---|---|
committer | Anatol Belski <ab@php.net> | 2019-02-08 18:10:31 -0800 |
commit | 12bfd9a5f58c12b8f63011c130ec3bf6605ea33b (patch) | |
tree | dc907993e27cad70d20e016fbe78a390ad53735a /win32 | |
parent | e1dd8cd678e72475fe28f450657fb81665beaccc (diff) | |
download | php-git-12bfd9a5f58c12b8f63011c130ec3bf6605ea33b.tar.gz |
Implement FR #77377 handle CTRL+C in Windows
Diffstat (limited to 'win32')
-rw-r--r-- | win32/build/config.w32 | 2 | ||||
-rw-r--r-- | win32/codepage.c | 13 | ||||
-rw-r--r-- | win32/console.c | 8 | ||||
-rw-r--r-- | win32/console.h | 3 | ||||
-rw-r--r-- | win32/signal.c | 172 | ||||
-rw-r--r-- | win32/signal.h | 3 |
6 files changed, 192 insertions, 9 deletions
diff --git a/win32/build/config.w32 b/win32/build/config.w32 index 9fbbe8b7d2..8c281d4667 100644 --- a/win32/build/config.w32 +++ b/win32/build/config.w32 @@ -268,7 +268,7 @@ if (VS_TOOLSET && VCVERS >= 1914) { ADD_SOURCES("win32", "dllmain.c glob.c readdir.c \ registry.c select.c sendmail.c time.c winutil.c wsyslog.c globals.c \ getrusage.c ftok.c ioutil.c codepage.c nice.c \ - inet.c fnmatch.c sockets.c console.c"); + inet.c fnmatch.c sockets.c console.c signal.c"); ADD_FLAG("CFLAGS_BD_WIN32", "/D ZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); if (VS_TOOLSET && VCVERS >= 1914) { diff --git a/win32/codepage.c b/win32/codepage.c index 839ba6d447..302fcb8b45 100644 --- a/win32/codepage.c +++ b/win32/codepage.c @@ -22,6 +22,8 @@ #include "SAPI.h" #include <emmintrin.h> +#include "win32/console.h" + ZEND_TLS const struct php_win32_cp *cur_cp = NULL; ZEND_TLS const struct php_win32_cp *orig_cp = NULL; ZEND_TLS const struct php_win32_cp *cur_out_cp = NULL; @@ -289,11 +291,6 @@ __forceinline static char *php_win32_cp_get_enc(void) return enc; }/*}}}*/ -__forceinline static BOOL php_win32_cp_is_cli_sapi() -{/*{{{*/ - return strlen(sapi_module.name) >= sizeof("cli") - 1 && !strncmp(sapi_module.name, "cli", sizeof("cli") - 1); -}/*}}}*/ - PW32CP const struct php_win32_cp *php_win32_cp_get_current(void) {/*{{{*/ return cur_cp; @@ -473,7 +470,7 @@ PW32CP const struct php_win32_cp *php_win32_cp_do_setup(const char *enc) if (!orig_cp) { orig_cp = php_win32_cp_get_by_id(GetACP()); } - if (php_win32_cp_is_cli_sapi()) { + if (php_win32_console_is_cli_sapi()) { if (!orig_in_cp) { orig_in_cp = php_win32_cp_get_by_id(GetConsoleCP()); if (!orig_in_cp) { @@ -499,7 +496,7 @@ PW32CP const struct php_win32_cp *php_win32_cp_do_update(const char *enc) } cur_cp = php_win32_cp_get_by_enc(enc); - if (php_win32_cp_is_cli_sapi()) { + if (php_win32_console_is_cli_sapi()) { php_win32_cp_cli_do_setup(cur_cp->id); } @@ -574,7 +571,7 @@ PHP_FUNCTION(sapi_windows_cp_set) RETURN_FALSE; } - if (php_win32_cp_is_cli_sapi()) { + if (php_win32_console_is_cli_sapi()) { cp = php_win32_cp_cli_do_setup((DWORD)id); } else { cp = php_win32_cp_set_by_id((DWORD)id); diff --git a/win32/console.c b/win32/console.c index 27dbd4548d..0b1bb0eff9 100644 --- a/win32/console.c +++ b/win32/console.c @@ -16,6 +16,8 @@ +----------------------------------------------------------------------+ */ +#include "php.h" +#include "SAPI.h" #include "win32/console.h" @@ -108,3 +110,9 @@ PHP_WINUTIL_API BOOL php_win32_console_is_own(void) return FALSE; }/*}}}*/ + +PHP_WINUTIL_API BOOL php_win32_console_is_cli_sapi(void) +{/*{{{*/ + return strlen(sapi_module.name) >= sizeof("cli") - 1 && !strncmp(sapi_module.name, "cli", sizeof("cli") - 1); +}/*}}}*/ + diff --git a/win32/console.h b/win32/console.h index 5e50eef8b1..2d36d85508 100644 --- a/win32/console.h +++ b/win32/console.h @@ -59,4 +59,7 @@ PHP_WINUTIL_API BOOL php_win32_console_fileno_set_vt100(zend_long fileno, BOOL e http://support.microsoft.com/kb/99115 */ PHP_WINUTIL_API BOOL php_win32_console_is_own(void); +/* Check whether the current SAPI is run on console. */ +PHP_WINUTIL_API BOOL php_win32_console_is_cli_sapi(void); + #endif diff --git a/win32/signal.c b/win32/signal.c new file mode 100644 index 0000000000..d682c42fbe --- /dev/null +++ b/win32/signal.c @@ -0,0 +1,172 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 7 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2019 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Anatol Belski <ab@php.net> | + +----------------------------------------------------------------------+ +*/ + +#include "php.h" +#include "SAPI.h" + +#include "win32/console.h" + +ZEND_TLS zval ctrl_handler; +ZEND_TLS DWORD ctrl_evt = (DWORD)-1; +ZEND_TLS zend_bool *vm_interrupt_flag = NULL; + +static void (*orig_interrupt_function)(zend_execute_data *execute_data); + +static void php_win32_signal_ctrl_interrupt_function(zend_execute_data *execute_data) +{/*{{{*/ + if (IS_UNDEF != Z_TYPE(ctrl_handler)) { + zval retval, params[1]; + + ZVAL_LONG(¶ms[0], ctrl_evt); + + /* If the function returns, */ + call_user_function(EG(function_table), NULL, &ctrl_handler, &retval, 1, params); + zval_ptr_dtor(&retval); + } + + if (orig_interrupt_function) { + orig_interrupt_function(execute_data); + } +}/*}}}*/ + +PHP_WINUTIL_API void php_win32_signal_ctrl_handler_init(void) +{/*{{{*/ + /* We are in the main thread! */ + if (!php_win32_console_is_cli_sapi()) { + return; + } + + orig_interrupt_function = zend_interrupt_function; + zend_interrupt_function = php_win32_signal_ctrl_interrupt_function; + vm_interrupt_flag = &EG(vm_interrupt); + ZVAL_UNDEF(&ctrl_handler); + + REGISTER_MAIN_LONG_CONSTANT("PHP_WINDOWS_EVENT_CTRL_C", CTRL_C_EVENT, CONST_PERSISTENT | CONST_CS); + REGISTER_MAIN_LONG_CONSTANT("PHP_WINDOWS_EVENT_CTRL_BREAK", CTRL_BREAK_EVENT, CONST_PERSISTENT | CONST_CS); +}/*}}}*/ + +PHP_WINUTIL_API void php_win32_signal_ctrl_handler_shutdown(void) +{/*{{{*/ + if (!php_win32_console_is_cli_sapi()) { + return; + } + + zend_interrupt_function = orig_interrupt_function; + orig_interrupt_function = NULL; + vm_interrupt_flag = NULL; + ZVAL_UNDEF(&ctrl_handler); +}/*}}}*/ + +static BOOL php_win32_signal_system_ctrl_handler(DWORD evt) +{/*{{{*/ + if (CTRL_C_EVENT != evt && CTRL_BREAK_EVENT != evt) { + return FALSE; + } + + (void)InterlockedExchange((LONG*)vm_interrupt_flag, 1); + + ctrl_evt = evt; + + return TRUE; +}/*}}}*/ + +/* {{{ proto bool sapi_windows_set_ctrl_handler(callable handler, [, bool add = true]) + Assigns a CTRL signal handler to a PHP function */ +PHP_FUNCTION(sapi_windows_set_ctrl_handler) +{ + zval *handler = NULL; + zend_bool add = 1; + +#if ZTS + if (!tsrm_is_main_thread()) { + php_error_docref(NULL, E_WARNING, "CTRL events can only be received on the main thread"); + return; + } +#endif + + if (!php_win32_console_is_cli_sapi()) { + php_error_docref(NULL, E_WARNING, "CTRL events trapping is only supported on console"); + return; + } + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|b", &handler, &add) == FAILURE) { + return; + } + + if (IS_NULL == Z_TYPE_P(handler)) { + zval_dtor(&ctrl_handler); + ZVAL_UNDEF(&ctrl_handler); + if (!SetConsoleCtrlHandler(NULL, add)) { + RETURN_FALSE; + } + RETURN_TRUE; + } + + if (!zend_is_callable(handler, 0, NULL)) { + zend_string *func_name = zend_get_callable_name(handler); + php_error_docref(NULL, E_WARNING, "%s is not a callable function name error", ZSTR_VAL(func_name)); + zend_string_release_ex(func_name, 0); + RETURN_FALSE; + } + + if (!SetConsoleCtrlHandler(NULL, FALSE) || !SetConsoleCtrlHandler(php_win32_signal_system_ctrl_handler, add)) { + zend_string *func_name = zend_get_callable_name(handler); + php_error_docref(NULL, E_WARNING, "Unable to attach %s as a CTRL handler", ZSTR_VAL(func_name)); + zend_string_release_ex(func_name, 0); + RETURN_FALSE; + } + + zval_dtor(&ctrl_handler); + ZVAL_COPY(&ctrl_handler, handler); + + RETURN_TRUE; +}/*}}}*/ + +PHP_FUNCTION(sapi_windows_generate_ctrl_event) +{/*{{{*/ + zend_long evt, pid = 0; + zend_bool ret = 0; + + if (!php_win32_console_is_cli_sapi()) { + php_error_docref(NULL, E_WARNING, "CTRL events trapping is only supported on console"); + return; + } + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|l", &evt, &pid) == FAILURE) { + return; + } + + SetConsoleCtrlHandler(NULL, TRUE); + + ret = (GenerateConsoleCtrlEvent(evt, pid) != 0); + + if (IS_UNDEF != Z_TYPE(ctrl_handler)) { + ret = ret && SetConsoleCtrlHandler(php_win32_signal_system_ctrl_handler, TRUE); + } + + RETURN_BOOL(ret); +}/*}}}*/ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: sw=4 ts=4 fdm=marker + * vim<600: sw=4 ts=4 + */ diff --git a/win32/signal.h b/win32/signal.h index ec739527ac..484a8d1c00 100644 --- a/win32/signal.h +++ b/win32/signal.h @@ -7,4 +7,7 @@ #define SIGVTALRM 26 /* virtual time alarm */ #define SIGPROF 27 /* profiling time alarm */ +PHP_WINUTIL_API void php_win32_signal_ctrl_handler_init(void); +PHP_WINUTIL_API void php_win32_signal_ctrl_handler_shutdown(void); + #endif /* PHP_WIN32_SIGNAL_H */ |