xref: /PHP-8.0/sapi/phpdbg/phpdbg_sigio_win32.c (revision 5d6e923d)
1 /*
2    +----------------------------------------------------------------------+
3    | Copyright (c) The PHP Group                                          |
4    +----------------------------------------------------------------------+
5    | This source file is subject to version 3.01 of the PHP license,      |
6    | that is bundled with this package in the file LICENSE, and is        |
7    | available through the world-wide-web at the following url:           |
8    | http://www.php.net/license/3_01.txt                                  |
9    | If you did not receive a copy of the PHP license and are unable to   |
10    | obtain it through the world-wide-web, please send a note to          |
11    | license@php.net so we can mail you a copy immediately.               |
12    +----------------------------------------------------------------------+
13    | Authors: Anatol Belski <ab@php.net>                                  |
14    +----------------------------------------------------------------------+
15 */
16 
17 
18 #include <signal.h>
19 
20 #include "phpdbg.h"
21 #include "phpdbg_sigio_win32.h"
22 
23 
ZEND_EXTERN_MODULE_GLOBALS(phpdbg)24 ZEND_EXTERN_MODULE_GLOBALS(phpdbg)
25 
26 
27 VOID
28 SigIoWatcherThread(VOID *p)
29 {
30 	zend_uchar sig;
31 	struct win32_sigio_watcher_data *swd = (struct win32_sigio_watcher_data *)p;
32 
33 top:
34 	(void)phpdbg_consume_bytes(swd->fd, &sig, 1, -1);
35 
36 
37 	if (3 == sig) {
38 		/* XXX completely not sure it is done right here */
39 		if (*swd->flags & PHPDBG_IS_INTERACTIVE) {
40 			if (raise(sig)) {
41 				goto top;
42 			}
43 		}
44 		if (*swd->flags & PHPDBG_IS_SIGNALED) {
45 			phpdbg_set_sigsafe_mem(&sig);
46 			zend_try {
47 				phpdbg_force_interruption();
48 			} zend_end_try();
49 			phpdbg_clear_sigsafe_mem();
50 			goto end;
51 		}
52 		if (!(*swd->flags & PHPDBG_IS_INTERACTIVE)) {
53 			*swd->flags |= PHPDBG_IS_SIGNALED;
54 		}
55 end:
56 		/* XXX set signaled flag to the caller thread, question is - whether it's needed */
57 		ExitThread(sig);
58 	} else {
59 		goto top;
60 	}
61 }
62 
63 
64 /* Start this only for the time of the run or eval command,
65 for so long that the main thread is busy serving some debug
66 session. */
67 void
sigio_watcher_start(void)68 sigio_watcher_start(void)
69 {
70 
71 	PHPDBG_G(swd).fd = PHPDBG_G(io)[PHPDBG_STDIN].fd;
72 #ifdef ZTS
73 	PHPDBG_G(swd).flags = &PHPDBG_G(flags);
74 #endif
75 
76 	PHPDBG_G(sigio_watcher_thread) = CreateThread(
77 		NULL,
78 		0,
79 		(LPTHREAD_START_ROUTINE)SigIoWatcherThread,
80 		&PHPDBG_G(swd),
81 		0,
82 		NULL);
83 }
84 
85 void
sigio_watcher_stop(void)86 sigio_watcher_stop(void)
87 {
88 	DWORD waited;
89 
90 	if (INVALID_HANDLE_VALUE == PHPDBG_G(sigio_watcher_thread)) {
91 		/* it probably did bail out already */
92 		return;
93 	}
94 
95 	waited = WaitForSingleObject(PHPDBG_G(sigio_watcher_thread), 300);
96 
97 	if (WAIT_OBJECT_0 != waited) {
98 		if (!CancelSynchronousIo(PHPDBG_G(sigio_watcher_thread))) {
99 			/* error out */
100 		}
101 
102 		if (!TerminateThread(PHPDBG_G(sigio_watcher_thread), 0)) {
103 			/* error out */
104 		}
105 	}
106 
107 	PHPDBG_G(swd).fd = -1;
108 	PHPDBG_G(sigio_watcher_thread) = INVALID_HANDLE_VALUE;
109 }
110