libuv-svace-build

Форк
0
282 строки · 8.0 Кб
1
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
2
 * Permission is hereby granted, free of charge, to any person obtaining a copy
3
 * of this software and associated documentation files (the "Software"), to
4
 * deal in the Software without restriction, including without limitation the
5
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
6
 * sell copies of the Software, and to permit persons to whom the Software is
7
 * furnished to do so, subject to the following conditions:
8
 *
9
 * The above copyright notice and this permission notice shall be included in
10
 * all copies or substantial portions of the Software.
11
 *
12
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
15
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
17
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
18
 * IN THE SOFTWARE.
19
 */
20

21
#include <assert.h>
22
#include <signal.h>
23

24
#include "uv.h"
25
#include "internal.h"
26
#include "handle-inl.h"
27
#include "req-inl.h"
28

29

30
RB_HEAD(uv_signal_tree_s, uv_signal_s);
31

32
static struct uv_signal_tree_s uv__signal_tree = RB_INITIALIZER(uv__signal_tree);
33
static CRITICAL_SECTION uv__signal_lock;
34

35
static BOOL WINAPI uv__signal_control_handler(DWORD type);
36

37
int uv__signal_start(uv_signal_t* handle,
38
                     uv_signal_cb signal_cb,
39
                     int signum,
40
                     int oneshot);
41

42
void uv__signals_init(void) {
43
  InitializeCriticalSection(&uv__signal_lock);
44
  if (!SetConsoleCtrlHandler(uv__signal_control_handler, TRUE))
45
    abort();
46
}
47

48

49
void uv__signal_cleanup(void) {
50
  /* TODO(bnoordhuis) Undo effects of uv_signal_init()? */
51
}
52

53

54
static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2) {
55
  /* Compare signums first so all watchers with the same signnum end up
56
   * adjacent. */
57
  if (w1->signum < w2->signum) return -1;
58
  if (w1->signum > w2->signum) return 1;
59

60
  /* Sort by loop pointer, so we can easily look up the first item after
61
   * { .signum = x, .loop = NULL }. */
62
  if ((uintptr_t) w1->loop < (uintptr_t) w2->loop) return -1;
63
  if ((uintptr_t) w1->loop > (uintptr_t) w2->loop) return 1;
64

65
  if ((uintptr_t) w1 < (uintptr_t) w2) return -1;
66
  if ((uintptr_t) w1 > (uintptr_t) w2) return 1;
67

68
  return 0;
69
}
70

71

72
RB_GENERATE_STATIC(uv_signal_tree_s, uv_signal_s, tree_entry, uv__signal_compare)
73

74

75
/*
76
 * Dispatches signal {signum} to all active uv_signal_t watchers in all loops.
77
 * Returns 1 if the signal was dispatched to any watcher, or 0 if there were
78
 * no active signal watchers observing this signal.
79
 */
80
int uv__signal_dispatch(int signum) {
81
  uv_signal_t lookup;
82
  uv_signal_t* handle;
83
  int dispatched;
84

85
  dispatched = 0;
86

87
  EnterCriticalSection(&uv__signal_lock);
88

89
  lookup.signum = signum;
90
  lookup.loop = NULL;
91

92
  for (handle = RB_NFIND(uv_signal_tree_s, &uv__signal_tree, &lookup);
93
       handle != NULL && handle->signum == signum;
94
       handle = RB_NEXT(uv_signal_tree_s, &uv__signal_tree, handle)) {
95
    unsigned long previous = InterlockedExchange(
96
            (volatile LONG*) &handle->pending_signum, signum);
97

98
    if (handle->flags & UV_SIGNAL_ONE_SHOT_DISPATCHED)
99
      continue;
100

101
    if (!previous) {
102
      POST_COMPLETION_FOR_REQ(handle->loop, &handle->signal_req);
103
    }
104

105
    dispatched = 1;
106
    if (handle->flags & UV_SIGNAL_ONE_SHOT)
107
      handle->flags |= UV_SIGNAL_ONE_SHOT_DISPATCHED;
108
  }
109

110
  LeaveCriticalSection(&uv__signal_lock);
111

112
  return dispatched;
113
}
114

115

116
static BOOL WINAPI uv__signal_control_handler(DWORD type) {
117
  switch (type) {
118
    case CTRL_C_EVENT:
119
      return uv__signal_dispatch(SIGINT);
120

121
    case CTRL_BREAK_EVENT:
122
      return uv__signal_dispatch(SIGBREAK);
123

124
    case CTRL_CLOSE_EVENT:
125
      if (uv__signal_dispatch(SIGHUP)) {
126
        /* Windows will terminate the process after the control handler
127
         * returns. After that it will just terminate our process. Therefore
128
         * block the signal handler so the main loop has some time to pick up
129
         * the signal and do something for a few seconds. */
130
        Sleep(INFINITE);
131
        return TRUE;
132
      }
133
      return FALSE;
134

135
    case CTRL_LOGOFF_EVENT:
136
    case CTRL_SHUTDOWN_EVENT:
137
      /* These signals are only sent to services. Services have their own
138
       * notification mechanism, so there's no point in handling these. */
139

140
    default:
141
      /* We don't handle these. */
142
      return FALSE;
143
  }
144
}
145

146

147
int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle) {
148
  uv__handle_init(loop, (uv_handle_t*) handle, UV_SIGNAL);
149
  handle->pending_signum = 0;
150
  handle->signum = 0;
151
  handle->signal_cb = NULL;
152

153
  UV_REQ_INIT(&handle->signal_req, UV_SIGNAL_REQ);
154
  handle->signal_req.data = handle;
155

156
  return 0;
157
}
158

159

160
int uv_signal_stop(uv_signal_t* handle) {
161
  uv_signal_t* removed_handle;
162

163
  /* If the watcher wasn't started, this is a no-op. */
164
  if (handle->signum == 0)
165
    return 0;
166

167
  EnterCriticalSection(&uv__signal_lock);
168

169
  removed_handle = RB_REMOVE(uv_signal_tree_s, &uv__signal_tree, handle);
170
  assert(removed_handle == handle);
171

172
  LeaveCriticalSection(&uv__signal_lock);
173

174
  handle->signum = 0;
175
  uv__handle_stop(handle);
176

177
  return 0;
178
}
179

180

181
int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) {
182
  return uv__signal_start(handle, signal_cb, signum, 0);
183
}
184

185

186
int uv_signal_start_oneshot(uv_signal_t* handle,
187
                            uv_signal_cb signal_cb,
188
                            int signum) {
189
  return uv__signal_start(handle, signal_cb, signum, 1);
190
}
191

192

193
int uv__signal_start(uv_signal_t* handle,
194
                            uv_signal_cb signal_cb,
195
                            int signum,
196
                            int oneshot) {
197
  /* Test for invalid signal values. */
198
  if (signum <= 0 || signum >= NSIG)
199
    return UV_EINVAL;
200

201
  /* Short circuit: if the signal watcher is already watching {signum} don't go
202
   * through the process of deregistering and registering the handler.
203
   * Additionally, this avoids pending signals getting lost in the (small) time
204
   * frame that handle->signum == 0. */
205
  if (signum == handle->signum) {
206
    handle->signal_cb = signal_cb;
207
    return 0;
208
  }
209

210
  /* If the signal handler was already active, stop it first. */
211
  if (handle->signum != 0) {
212
    int r = uv_signal_stop(handle);
213
    /* uv_signal_stop is infallible. */
214
    assert(r == 0);
215
  }
216

217
  EnterCriticalSection(&uv__signal_lock);
218

219
  handle->signum = signum;
220
  if (oneshot)
221
    handle->flags |= UV_SIGNAL_ONE_SHOT;
222

223
  RB_INSERT(uv_signal_tree_s, &uv__signal_tree, handle);
224

225
  LeaveCriticalSection(&uv__signal_lock);
226

227
  handle->signal_cb = signal_cb;
228
  uv__handle_start(handle);
229

230
  return 0;
231
}
232

233

234
void uv__process_signal_req(uv_loop_t* loop, uv_signal_t* handle,
235
    uv_req_t* req) {
236
  long dispatched_signum;
237

238
  assert(handle->type == UV_SIGNAL);
239
  assert(req->type == UV_SIGNAL_REQ);
240

241
  dispatched_signum = InterlockedExchange(
242
          (volatile LONG*) &handle->pending_signum, 0);
243
  assert(dispatched_signum != 0);
244

245
  /* Check if the pending signal equals the signum that we are watching for.
246
   * These can get out of sync when the handler is stopped and restarted while
247
   * the signal_req is pending. */
248
  if (dispatched_signum == handle->signum)
249
    handle->signal_cb(handle, dispatched_signum);
250

251
  if (handle->flags & UV_SIGNAL_ONE_SHOT)
252
    uv_signal_stop(handle);
253

254
  if (handle->flags & UV_HANDLE_CLOSING) {
255
    /* When it is closing, it must be stopped at this point. */
256
    assert(handle->signum == 0);
257
    uv__want_endgame(loop, (uv_handle_t*) handle);
258
  }
259
}
260

261

262
void uv__signal_close(uv_loop_t* loop, uv_signal_t* handle) {
263
  uv_signal_stop(handle);
264
  uv__handle_closing(handle);
265

266
  if (handle->pending_signum == 0) {
267
    uv__want_endgame(loop, (uv_handle_t*) handle);
268
  }
269
}
270

271

272
void uv__signal_endgame(uv_loop_t* loop, uv_signal_t* handle) {
273
  assert(handle->flags & UV_HANDLE_CLOSING);
274
  assert(!(handle->flags & UV_HANDLE_CLOSED));
275

276
  assert(handle->signum == 0);
277
  assert(handle->pending_signum == 0);
278

279
  handle->flags |= UV_HANDLE_CLOSED;
280

281
  uv__handle_close(handle);
282
}
283

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.