1 /*
2  * %CopyrightBegin%
3  *
4  * Copyright Ericsson AB 1997-2018. All Rights Reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  * %CopyrightEnd%
19  */
20 /*
21  * Purpose: Interrupt handling in windows.
22  */
23 #ifdef HAVE_CONFIG_H
24 #  include "config.h"
25 #endif
26 #include "sys.h"
27 #include "erl_alloc.h"
28 #include "erl_thr_progress.h"
29 #include "erl_driver.h"
30 #include "../../drivers/win32/win_con.h"
31 
32 #if defined(__GNUC__)
33 #  define WIN_SYS_INLINE __inline__
34 #elif defined(__WIN32__)
35 #  define WIN_SYS_INLINE __forceinline
36 #endif
37 
38 erts_atomic32_t erts_break_requested;
39 #define ERTS_SET_BREAK_REQUESTED \
40   erts_atomic32_set_nob(&erts_break_requested, (erts_aint32_t) 1)
41 #define ERTS_UNSET_BREAK_REQUESTED \
42   erts_atomic32_set_nob(&erts_break_requested, (erts_aint32_t) 0)
43 
44 extern int nohup;
45 HANDLE erts_sys_break_event = NULL;
46 
erts_do_break_handling(void)47 void erts_do_break_handling(void)
48 {
49     /*
50      * Most functions that do_break() calls are intentionally not thread safe;
51      * therefore, make sure that all threads but this one are blocked before
52      * proceeding!
53      */
54     erts_thr_progress_block();
55     /* call the break handling function, reset the flag */
56     do_break();
57 
58     ResetEvent(erts_sys_break_event);
59     ERTS_UNSET_BREAK_REQUESTED;
60 
61     erts_thr_progress_unblock();
62 }
63 
64 
ctrl_handler_ignore_break(DWORD dwCtrlType)65 BOOL WINAPI ctrl_handler_ignore_break(DWORD dwCtrlType)
66 {
67     switch (dwCtrlType) {
68     case CTRL_C_EVENT:
69     case CTRL_BREAK_EVENT:
70 	return TRUE;
71 	break;
72     case CTRL_LOGOFF_EVENT:
73     case CTRL_SHUTDOWN_EVENT:
74 	if (nohup)
75 	    return TRUE;
76 	/* else pour through... */
77     case CTRL_CLOSE_EVENT:
78 	erts_exit(0, "");
79 	break;
80     }
81     return TRUE;
82 }
83 
erts_set_ignore_break(void)84 void erts_set_ignore_break(void) {
85     ConSetCtrlHandler(ctrl_handler_ignore_break);
86     SetConsoleCtrlHandler(ctrl_handler_ignore_break, TRUE);
87 }
88 
ctrl_handler_replace_intr(DWORD dwCtrlType)89 BOOL WINAPI ctrl_handler_replace_intr(DWORD dwCtrlType)
90 {
91     switch (dwCtrlType) {
92     case CTRL_C_EVENT:
93 	return FALSE;
94     case CTRL_BREAK_EVENT:
95 	SetEvent(erts_sys_break_event);
96 	break;
97     case CTRL_LOGOFF_EVENT:
98 	if (nohup)
99 	    return TRUE;
100 	/* else pour through... */
101     case CTRL_CLOSE_EVENT:
102     case CTRL_SHUTDOWN_EVENT:
103 	erts_exit(0, "");
104 	break;
105     }
106     return TRUE;
107 }
108 
109 
110 /* Don't use ctrl-c for break handler but let it be
111    used by the shell instead (see user_drv.erl) */
erts_replace_intr(void)112 void erts_replace_intr(void) {
113     ConSetCtrlHandler(ctrl_handler_replace_intr);
114     SetConsoleCtrlHandler(ctrl_handler_replace_intr, TRUE);
115 }
116 
ctrl_handler(DWORD dwCtrlType)117 BOOL WINAPI ctrl_handler(DWORD dwCtrlType)
118 {
119     switch (dwCtrlType) {
120     case CTRL_C_EVENT:
121     case CTRL_BREAK_EVENT:
122 	SetEvent(erts_sys_break_event);
123 	break;
124     case CTRL_LOGOFF_EVENT:
125     case CTRL_SHUTDOWN_EVENT:
126 	if (nohup)
127 	    return TRUE;
128 	/* else pour through... */
129     case CTRL_CLOSE_EVENT:
130 	erts_exit(0, "");
131 	break;
132     }
133     return TRUE;
134 }
135 
init_break_handler()136 void init_break_handler()
137 {
138     ConSetCtrlHandler(ctrl_handler);
139     SetConsoleCtrlHandler(ctrl_handler, TRUE);
140 }
141 
142