summaryrefslogtreecommitdiff
path: root/win32
diff options
context:
space:
mode:
authorAnatol Belski <ab@php.net>2019-02-08 18:10:31 -0800
committerAnatol Belski <ab@php.net>2019-02-08 18:10:31 -0800
commit12bfd9a5f58c12b8f63011c130ec3bf6605ea33b (patch)
treedc907993e27cad70d20e016fbe78a390ad53735a /win32
parente1dd8cd678e72475fe28f450657fb81665beaccc (diff)
downloadphp-git-12bfd9a5f58c12b8f63011c130ec3bf6605ea33b.tar.gz
Implement FR #77377 handle CTRL+C in Windows
Diffstat (limited to 'win32')
-rw-r--r--win32/build/config.w322
-rw-r--r--win32/codepage.c13
-rw-r--r--win32/console.c8
-rw-r--r--win32/console.h3
-rw-r--r--win32/signal.c172
-rw-r--r--win32/signal.h3
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(&params[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 */