noderb 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +157 -7
- data/ext/noderb_extension/extconf.rb +1 -3
- data/ext/noderb_extension/libuv/BSDmakefile +2 -0
- data/ext/noderb_extension/libuv/all.gyp +326 -0
- data/ext/noderb_extension/libuv/config-mingw.mk +0 -1
- data/ext/noderb_extension/libuv/config-unix.mk +7 -1
- data/ext/noderb_extension/libuv/create-msvs-files.bat +13 -6
- data/ext/noderb_extension/libuv/{build/gyp_uv → gyp_uv} +1 -2
- data/ext/noderb_extension/libuv/include/uv.h +5 -0
- data/ext/noderb_extension/libuv/src/eio/config_cygwin.h +3 -0
- data/ext/noderb_extension/libuv/src/eio/config_freebsd.h +3 -0
- data/ext/noderb_extension/libuv/src/eio/config_sunos.h +3 -0
- data/ext/noderb_extension/libuv/src/eio/ecb.h +1 -1
- data/ext/noderb_extension/libuv/src/eio/eio.c +8 -1
- data/ext/noderb_extension/libuv/src/uv-common.c +1 -0
- data/ext/noderb_extension/libuv/src/uv-sunos.c +1 -1
- data/ext/noderb_extension/libuv/src/uv-unix.c +72 -59
- data/ext/noderb_extension/libuv/src/win/core.c +3 -0
- data/ext/noderb_extension/libuv/src/win/internal.h +11 -0
- data/ext/noderb_extension/libuv/src/win/ntdll.h +130 -0
- data/ext/noderb_extension/libuv/src/win/pipe.c +105 -27
- data/ext/noderb_extension/libuv/src/win/process.c +76 -5
- data/ext/noderb_extension/libuv/src/win/req.c +7 -0
- data/ext/noderb_extension/libuv/src/win/winapi.c +52 -0
- data/ext/noderb_extension/libuv/test/benchmark-pound.c +50 -48
- data/ext/noderb_extension/libuv/test/echo-server.c +2 -2
- data/ext/noderb_extension/libuv/test/test-list.h +2 -0
- data/ext/noderb_extension/libuv/test/test-spawn.c +48 -1
- data/ext/noderb_extension/noderb.c +38 -339
- data/ext/noderb_extension/noderb.h +18 -2
- data/ext/noderb_extension/noderb_common.h +13 -0
- data/ext/noderb_extension/noderb_dns.c +37 -0
- data/ext/noderb_extension/noderb_dns.h +15 -0
- data/ext/noderb_extension/noderb_process.c +126 -0
- data/ext/noderb_extension/noderb_process.h +17 -0
- data/ext/noderb_extension/noderb_tcp.c +127 -0
- data/ext/noderb_extension/noderb_tcp.h +19 -0
- data/ext/noderb_extension/noderb_timers.c +58 -0
- data/ext/noderb_extension/noderb_timers.h +16 -0
- data/ext/noderb_extension/noderb_tools.c +127 -0
- data/ext/noderb_extension/noderb_tools.h +33 -0
- data/lib/noderb/dns.rb +11 -0
- data/lib/noderb/next_tick.rb +2 -1
- data/lib/noderb/tcp.rb +27 -0
- data/lib/noderb/timers.rb +24 -0
- data/lib/noderb/version.rb +1 -1
- data/lib/noderb.rb +6 -1
- metadata +23 -7
- data/ext/noderb_extension/libuv/build/all.gyp +0 -254
- data/ext/noderb_extension/libuv/doc/desired-api.md +0 -159
- /data/ext/noderb_extension/libuv/{build/common.gypi → common.gypi} +0 -0
@@ -56,9 +56,9 @@ int uv_pipe_init_with_handle(uv_pipe_t* handle, HANDLE pipeHandle) {
|
|
56
56
|
int err = uv_pipe_init(handle);
|
57
57
|
|
58
58
|
if (!err) {
|
59
|
-
/*
|
59
|
+
/*
|
60
60
|
* At this point we don't know whether the pipe will be used as a client
|
61
|
-
* or a server. So, we assume that it will be a client until
|
61
|
+
* or a server. So, we assume that it will be a client until
|
62
62
|
* uv_listen is called.
|
63
63
|
*/
|
64
64
|
handle->handle = pipeHandle;
|
@@ -144,23 +144,92 @@ static int uv_set_pipe_handle(uv_pipe_t* handle, HANDLE pipeHandle) {
|
|
144
144
|
}
|
145
145
|
|
146
146
|
|
147
|
+
static DWORD WINAPI pipe_shutdown_thread_proc(void* parameter) {
|
148
|
+
int errno;
|
149
|
+
uv_pipe_t* handle;
|
150
|
+
uv_shutdown_t* req;
|
151
|
+
|
152
|
+
req = (uv_shutdown_t*) parameter;
|
153
|
+
assert(req);
|
154
|
+
handle = (uv_pipe_t*) req->handle;
|
155
|
+
assert(handle);
|
156
|
+
|
157
|
+
FlushFileBuffers(handle->handle);
|
158
|
+
|
159
|
+
/* Post completed */
|
160
|
+
if (!PostQueuedCompletionStatus(LOOP->iocp,
|
161
|
+
0,
|
162
|
+
0,
|
163
|
+
&req->overlapped)) {
|
164
|
+
uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
|
165
|
+
}
|
166
|
+
|
167
|
+
return 0;
|
168
|
+
}
|
169
|
+
|
170
|
+
|
147
171
|
void uv_pipe_endgame(uv_pipe_t* handle) {
|
148
172
|
uv_err_t err;
|
149
173
|
int status;
|
150
174
|
unsigned int uv_alloced;
|
175
|
+
DWORD result;
|
176
|
+
uv_shutdown_t* req;
|
177
|
+
NTSTATUS nt_status;
|
178
|
+
IO_STATUS_BLOCK io_status;
|
179
|
+
FILE_PIPE_LOCAL_INFORMATION pipe_info;
|
180
|
+
|
151
181
|
|
152
182
|
if (handle->flags & UV_HANDLE_SHUTTING &&
|
153
183
|
!(handle->flags & UV_HANDLE_SHUT) &&
|
154
184
|
handle->write_reqs_pending == 0) {
|
155
|
-
|
185
|
+
req = handle->shutdown_req;
|
186
|
+
|
187
|
+
/* Try to avoid flushing the pipe buffer in the thread pool. */
|
188
|
+
nt_status = pNtQueryInformationFile(handle->handle,
|
189
|
+
&io_status,
|
190
|
+
&pipe_info,
|
191
|
+
sizeof pipe_info,
|
192
|
+
FilePipeLocalInformation);
|
193
|
+
|
194
|
+
if (nt_status != STATUS_SUCCESS) {
|
195
|
+
/* Failure */
|
196
|
+
handle->flags &= ~UV_HANDLE_SHUTTING;
|
197
|
+
if (req->cb) {
|
198
|
+
uv_set_sys_error(pRtlNtStatusToDosError(nt_status));
|
199
|
+
req->cb(req, -1);
|
200
|
+
}
|
201
|
+
DECREASE_PENDING_REQ_COUNT(handle);
|
202
|
+
return;
|
203
|
+
}
|
156
204
|
|
157
|
-
if (
|
158
|
-
|
159
|
-
|
205
|
+
if (pipe_info.OutboundQuota == pipe_info.WriteQuotaAvailable) {
|
206
|
+
/* Short-circuit, no need to call FlushFileBuffers. */
|
207
|
+
handle->flags |= UV_HANDLE_SHUT;
|
208
|
+
if (req->cb) {
|
209
|
+
req->cb(req, 0);
|
160
210
|
}
|
161
|
-
|
211
|
+
DECREASE_PENDING_REQ_COUNT(handle);
|
212
|
+
return;
|
213
|
+
}
|
214
|
+
|
215
|
+
/* Run FlushFileBuffers in the thhead pool. */
|
216
|
+
result = QueueUserWorkItem(pipe_shutdown_thread_proc,
|
217
|
+
req,
|
218
|
+
WT_EXECUTELONGFUNCTION);
|
219
|
+
if (result) {
|
220
|
+
/* Mark the handle as shut now to avoid going through this again. */
|
221
|
+
handle->flags |= UV_HANDLE_SHUT;
|
222
|
+
|
223
|
+
} else {
|
224
|
+
/* Failure. */
|
225
|
+
handle->flags &= ~UV_HANDLE_SHUTTING;
|
226
|
+
if (req->cb) {
|
227
|
+
uv_set_sys_error(GetLastError());
|
228
|
+
req->cb(req, -1);
|
229
|
+
}
|
230
|
+
DECREASE_PENDING_REQ_COUNT(handle);
|
231
|
+
return;
|
162
232
|
}
|
163
|
-
handle->reqs_pending--;
|
164
233
|
}
|
165
234
|
|
166
235
|
if (handle->flags & UV_HANDLE_CLOSING &&
|
@@ -298,6 +367,8 @@ static DWORD WINAPI pipe_connect_thread_proc(void* parameter) {
|
|
298
367
|
if (pipeHandle != INVALID_HANDLE_VALUE) {
|
299
368
|
break;
|
300
369
|
}
|
370
|
+
|
371
|
+
SwitchToThread();
|
301
372
|
}
|
302
373
|
|
303
374
|
if (pipeHandle != INVALID_HANDLE_VALUE && !uv_set_pipe_handle(handle, pipeHandle)) {
|
@@ -317,8 +388,6 @@ static DWORD WINAPI pipe_connect_thread_proc(void* parameter) {
|
|
317
388
|
uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
|
318
389
|
}
|
319
390
|
|
320
|
-
handle->reqs_pending++;
|
321
|
-
|
322
391
|
return 0;
|
323
392
|
}
|
324
393
|
|
@@ -363,6 +432,8 @@ int uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle,
|
|
363
432
|
goto error;
|
364
433
|
}
|
365
434
|
|
435
|
+
handle->reqs_pending++;
|
436
|
+
|
366
437
|
return 0;
|
367
438
|
}
|
368
439
|
|
@@ -518,7 +589,7 @@ int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) {
|
|
518
589
|
return -1;
|
519
590
|
}
|
520
591
|
|
521
|
-
if (!(handle->flags & UV_HANDLE_BOUND) &&
|
592
|
+
if (!(handle->flags & UV_HANDLE_BOUND) &&
|
522
593
|
!(handle->flags & UV_HANDLE_GIVEN_OS_HANDLE)) {
|
523
594
|
uv_set_error(UV_EINVAL, 0);
|
524
595
|
return -1;
|
@@ -530,7 +601,7 @@ int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) {
|
|
530
601
|
return -1;
|
531
602
|
}
|
532
603
|
|
533
|
-
if (!(handle->flags & UV_HANDLE_PIPESERVER) &&
|
604
|
+
if (!(handle->flags & UV_HANDLE_PIPESERVER) &&
|
534
605
|
!(handle->flags & UV_HANDLE_GIVEN_OS_HANDLE)) {
|
535
606
|
uv_set_error(UV_ENOTSUP, 0);
|
536
607
|
return -1;
|
@@ -718,7 +789,10 @@ void uv_process_pipe_read_req(uv_pipe_t* handle, uv_req_t* req) {
|
|
718
789
|
break;
|
719
790
|
}
|
720
791
|
|
721
|
-
|
792
|
+
if (avail == 0) {
|
793
|
+
/* There is nothing to read after all. */
|
794
|
+
break;
|
795
|
+
}
|
722
796
|
|
723
797
|
buf = handle->alloc_cb((uv_stream_t*)handle, avail);
|
724
798
|
assert(buf.len > 0);
|
@@ -728,20 +802,10 @@ void uv_process_pipe_read_req(uv_pipe_t* handle, uv_req_t* req) {
|
|
728
802
|
buf.len,
|
729
803
|
&bytes,
|
730
804
|
NULL)) {
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
if (bytes <= buf.len) {
|
736
|
-
break;
|
737
|
-
}
|
738
|
-
} else {
|
739
|
-
/* Connection closed */
|
740
|
-
handle->flags &= ~UV_HANDLE_READING;
|
741
|
-
handle->flags |= UV_HANDLE_EOF;
|
742
|
-
LOOP->last_error.code = UV_EOF;
|
743
|
-
LOOP->last_error.sys_errno_ = ERROR_SUCCESS;
|
744
|
-
handle->read_cb((uv_stream_t*)handle, -1, buf);
|
805
|
+
/* Successful read */
|
806
|
+
handle->read_cb((uv_stream_t*)handle, bytes, buf);
|
807
|
+
/* Read again only if bytes == buf.len */
|
808
|
+
if (bytes <= buf.len) {
|
745
809
|
break;
|
746
810
|
}
|
747
811
|
} else {
|
@@ -826,3 +890,17 @@ void uv_process_pipe_connect_req(uv_pipe_t* handle, uv_connect_t* req) {
|
|
826
890
|
|
827
891
|
DECREASE_PENDING_REQ_COUNT(handle);
|
828
892
|
}
|
893
|
+
|
894
|
+
|
895
|
+
void uv_process_pipe_shutdown_req(uv_pipe_t* handle, uv_shutdown_t* req) {
|
896
|
+
assert(handle->type == UV_NAMED_PIPE);
|
897
|
+
|
898
|
+
CloseHandle(handle->handle);
|
899
|
+
handle->handle = INVALID_HANDLE_VALUE;
|
900
|
+
|
901
|
+
if (req->cb) {
|
902
|
+
req->cb(req, 0);
|
903
|
+
}
|
904
|
+
|
905
|
+
DECREASE_PENDING_REQ_COUNT(handle);
|
906
|
+
}
|
@@ -28,6 +28,16 @@
|
|
28
28
|
#include <stdlib.h>
|
29
29
|
#include <windows.h>
|
30
30
|
|
31
|
+
typedef struct env_var {
|
32
|
+
const char* narrow;
|
33
|
+
const wchar_t* wide;
|
34
|
+
int len; /* including null or '=' */
|
35
|
+
int supplied;
|
36
|
+
int value_len;
|
37
|
+
} env_var_t;
|
38
|
+
|
39
|
+
#define E_V(str) { str "=", L##str, sizeof(str), 0, 0 }
|
40
|
+
|
31
41
|
#define UTF8_TO_UTF16(s, t) \
|
32
42
|
size = uv_utf8_to_utf16(s, NULL, 0) * sizeof(wchar_t); \
|
33
43
|
t = (wchar_t*)malloc(size); \
|
@@ -361,6 +371,7 @@ static wchar_t* search_path(const wchar_t *file,
|
|
361
371
|
return result;
|
362
372
|
}
|
363
373
|
|
374
|
+
|
364
375
|
/*
|
365
376
|
* Quotes command line arguments
|
366
377
|
* Returns a pointer to the end (next char to be written) of the buffer
|
@@ -437,6 +448,7 @@ wchar_t* quote_cmd_arg(const wchar_t *source, wchar_t *target) {
|
|
437
448
|
return target;
|
438
449
|
}
|
439
450
|
|
451
|
+
|
440
452
|
wchar_t* make_program_args(char** args, int verbatim_arguments) {
|
441
453
|
wchar_t* dst;
|
442
454
|
wchar_t* ptr;
|
@@ -494,23 +506,69 @@ error:
|
|
494
506
|
return NULL;
|
495
507
|
}
|
496
508
|
|
509
|
+
|
510
|
+
/*
|
511
|
+
* If we learn that people are passing in huge environment blocks
|
512
|
+
* then we should probably qsort() the array and then bsearch()
|
513
|
+
* to see if it contains this variable. But there are ownership
|
514
|
+
* issues associated with that solution; this is the caller's
|
515
|
+
* char**, and modifying it is rude.
|
516
|
+
*/
|
517
|
+
static void check_required_vars_contains_var(env_var_t* required, int size, const char* var) {
|
518
|
+
int i;
|
519
|
+
for (i = 0; i < size; ++i) {
|
520
|
+
if (_strnicmp(required[i].narrow, var, required[i].len) == 0) {
|
521
|
+
required[i].supplied = 1;
|
522
|
+
return;
|
523
|
+
}
|
524
|
+
}
|
525
|
+
}
|
526
|
+
|
527
|
+
|
497
528
|
/*
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
529
|
+
* The way windows takes environment variables is different than what C does;
|
530
|
+
* Windows wants a contiguous block of null-terminated strings, terminated
|
531
|
+
* with an additional null.
|
532
|
+
*
|
533
|
+
* Windows has a few "essential" environment variables. winsock will fail
|
534
|
+
* to initialize if SYSTEMROOT is not defined; some APIs make reference to
|
535
|
+
* TEMP. SYSTEMDRIVE is probably also important. We therefore ensure that
|
536
|
+
* these get defined if the input environment block does not contain any
|
537
|
+
* values for them.
|
538
|
+
*/
|
502
539
|
wchar_t* make_program_env(char** env_block) {
|
503
540
|
wchar_t* dst;
|
504
541
|
wchar_t* ptr;
|
505
542
|
char** env;
|
506
543
|
int env_len = 1 * sizeof(wchar_t); /* room for closing null */
|
507
544
|
int len;
|
545
|
+
int i;
|
546
|
+
DWORD var_size;
|
547
|
+
|
548
|
+
env_var_t required_vars[] = {
|
549
|
+
E_V("SYSTEMROOT"),
|
550
|
+
E_V("SYSTEMDRIVE"),
|
551
|
+
E_V("TEMP"),
|
552
|
+
};
|
508
553
|
|
509
554
|
for (env = env_block; *env; env++) {
|
555
|
+
check_required_vars_contains_var(required_vars, COUNTOF(required_vars), *env);
|
510
556
|
env_len += (uv_utf8_to_utf16(*env, NULL, 0) * sizeof(wchar_t));
|
511
557
|
}
|
512
558
|
|
513
|
-
|
559
|
+
for (i = 0; i < COUNTOF(required_vars); ++i) {
|
560
|
+
if (!required_vars[i].supplied) {
|
561
|
+
env_len += required_vars[i].len * sizeof(wchar_t);
|
562
|
+
var_size = GetEnvironmentVariableW(required_vars[i].wide, NULL, 0);
|
563
|
+
if (var_size == 0) {
|
564
|
+
uv_fatal_error(GetLastError(), "GetEnvironmentVariableW");
|
565
|
+
}
|
566
|
+
required_vars[i].value_len = (int)var_size;
|
567
|
+
env_len += (int)var_size * sizeof(wchar_t);
|
568
|
+
}
|
569
|
+
}
|
570
|
+
|
571
|
+
dst = malloc(env_len);
|
514
572
|
if (!dst) {
|
515
573
|
uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
|
516
574
|
}
|
@@ -525,6 +583,19 @@ wchar_t* make_program_env(char** env_block) {
|
|
525
583
|
}
|
526
584
|
}
|
527
585
|
|
586
|
+
for (i = 0; i < COUNTOF(required_vars); ++i) {
|
587
|
+
if (!required_vars[i].supplied) {
|
588
|
+
wcscpy(ptr, required_vars[i].wide);
|
589
|
+
ptr += required_vars[i].len - 1;
|
590
|
+
*ptr++ = L'=';
|
591
|
+
var_size = GetEnvironmentVariableW(required_vars[i].wide, ptr, required_vars[i].value_len);
|
592
|
+
if (var_size == 0) {
|
593
|
+
uv_fatal_error(GetLastError(), "GetEnvironmentVariableW");
|
594
|
+
}
|
595
|
+
ptr += required_vars[i].value_len;
|
596
|
+
}
|
597
|
+
}
|
598
|
+
|
528
599
|
*ptr = L'\0';
|
529
600
|
return dst;
|
530
601
|
}
|
@@ -110,6 +110,13 @@ void uv_process_reqs() {
|
|
110
110
|
DELEGATE_STREAM_REQ((uv_connect_t*) req, connect, handle);
|
111
111
|
break;
|
112
112
|
|
113
|
+
case UV_SHUTDOWN:
|
114
|
+
/* Tcp shutdown requests don't come here. */
|
115
|
+
assert(((uv_shutdown_t*) req)->handle->type == UV_NAMED_PIPE);
|
116
|
+
uv_process_pipe_shutdown_req(
|
117
|
+
(uv_pipe_t*) ((uv_shutdown_t*) req)->handle, req);
|
118
|
+
break;
|
119
|
+
|
113
120
|
case UV_WAKEUP:
|
114
121
|
uv_process_async_wakeup_req((uv_async_t*) req->data, req);
|
115
122
|
break;
|
@@ -0,0 +1,52 @@
|
|
1
|
+
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
2
|
+
*
|
3
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
* of this software and associated documentation files (the "Software"), to
|
5
|
+
* deal in the Software without restriction, including without limitation the
|
6
|
+
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
7
|
+
* sell copies of the Software, and to permit persons to whom the Software is
|
8
|
+
* furnished to do so, subject to the following conditions:
|
9
|
+
*
|
10
|
+
* The above copyright notice and this permission notice shall be included in
|
11
|
+
* all copies or substantial portions of the Software.
|
12
|
+
*
|
13
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
18
|
+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
19
|
+
* IN THE SOFTWARE.
|
20
|
+
*/
|
21
|
+
|
22
|
+
#include <assert.h>
|
23
|
+
|
24
|
+
#include "uv.h"
|
25
|
+
#include "../uv-common.h"
|
26
|
+
#include "internal.h"
|
27
|
+
|
28
|
+
|
29
|
+
sRtlNtStatusToDosError pRtlNtStatusToDosError;
|
30
|
+
sNtQueryInformationFile pNtQueryInformationFile;
|
31
|
+
|
32
|
+
|
33
|
+
void uv_winapi_init() {
|
34
|
+
HMODULE module;
|
35
|
+
|
36
|
+
module = GetModuleHandleA("ntdll.dll");
|
37
|
+
if (module == NULL) {
|
38
|
+
uv_fatal_error(GetLastError(), "GetModuleHandleA");
|
39
|
+
}
|
40
|
+
|
41
|
+
pRtlNtStatusToDosError = (sRtlNtStatusToDosError) GetProcAddress(module,
|
42
|
+
"RtlNtStatusToDosError");
|
43
|
+
if (pRtlNtStatusToDosError == NULL) {
|
44
|
+
uv_fatal_error(GetLastError(), "GetProcAddress");
|
45
|
+
}
|
46
|
+
|
47
|
+
pNtQueryInformationFile = (sNtQueryInformationFile) GetProcAddress(module,
|
48
|
+
"NtQueryInformationFile");
|
49
|
+
if (pNtQueryInformationFile == NULL) {
|
50
|
+
uv_fatal_error(GetLastError(), "GetProcAddress");
|
51
|
+
}
|
52
|
+
}
|
@@ -22,6 +22,12 @@
|
|
22
22
|
#include "task.h"
|
23
23
|
#include "uv.h"
|
24
24
|
|
25
|
+
/* Update this is you're going to run > 1000 concurrent requests. */
|
26
|
+
#define MAX_CONNS 1000
|
27
|
+
|
28
|
+
#undef NANOSEC
|
29
|
+
#define NANOSEC ((uint64_t)10e8)
|
30
|
+
|
25
31
|
/* Base class for tcp_conn_rec and pipe_conn_rec.
|
26
32
|
* The ordering of fields matters!
|
27
33
|
*/
|
@@ -45,8 +51,13 @@ typedef struct {
|
|
45
51
|
|
46
52
|
static char buffer[] = "QS";
|
47
53
|
|
48
|
-
static
|
49
|
-
static
|
54
|
+
static tcp_conn_rec tcp_conns[MAX_CONNS];
|
55
|
+
static pipe_conn_rec pipe_conns[MAX_CONNS];
|
56
|
+
|
57
|
+
static uint64_t start_time;
|
58
|
+
static uint64_t end_time;
|
59
|
+
static int closed_streams;
|
60
|
+
static int conns_failed;
|
50
61
|
|
51
62
|
typedef void *(*setup_fn)(int num, void* arg);
|
52
63
|
typedef int (*connect_fn)(int num, void* handles, void* arg);
|
@@ -71,6 +82,12 @@ static void connect_cb(uv_connect_t* req, int status) {
|
|
71
82
|
uv_buf_t buf;
|
72
83
|
int r;
|
73
84
|
|
85
|
+
if (status != 0) {
|
86
|
+
uv_close((uv_handle_t*)req->handle, close_cb);
|
87
|
+
conns_failed++;
|
88
|
+
return;
|
89
|
+
}
|
90
|
+
|
74
91
|
ASSERT(req != NULL);
|
75
92
|
ASSERT(status == 0);
|
76
93
|
|
@@ -98,63 +115,34 @@ static void read_cb(uv_stream_t* stream, ssize_t nread, uv_buf_t buf) {
|
|
98
115
|
static void close_cb(uv_handle_t* handle) {
|
99
116
|
ASSERT(handle != NULL);
|
100
117
|
closed_streams++;
|
101
|
-
|
102
|
-
if (closed_streams == concurrency) {
|
103
|
-
uv_update_time();
|
104
|
-
end_time = uv_now();
|
105
|
-
}
|
106
118
|
}
|
107
119
|
|
108
120
|
|
109
121
|
static void* tcp_do_setup(int num, void* arg) {
|
110
|
-
tcp_conn_rec* conns;
|
111
122
|
tcp_conn_rec* pe;
|
112
123
|
tcp_conn_rec* p;
|
113
124
|
int r;
|
114
125
|
|
115
|
-
|
116
|
-
closed_streams = 0;
|
117
|
-
|
118
|
-
conns = calloc(num, sizeof(tcp_conn_rec));
|
119
|
-
ASSERT(conns != NULL);
|
120
|
-
|
121
|
-
for (p = conns, pe = p + num; p < pe; p++) {
|
126
|
+
for (p = tcp_conns, pe = p + num; p < pe; p++) {
|
122
127
|
r = uv_tcp_init(&p->stream);
|
123
128
|
ASSERT(r == 0);
|
124
|
-
p->stream.data = p;
|
125
|
-
p->conn_req.data = p;
|
126
|
-
p->write_req.data = p;
|
127
|
-
p->conn_req.handle = (uv_stream_t*)&p->stream;
|
128
|
-
p->write_req.handle = (uv_stream_t*)&p->stream;
|
129
129
|
}
|
130
130
|
|
131
|
-
return
|
131
|
+
return tcp_conns;
|
132
132
|
}
|
133
133
|
|
134
134
|
|
135
135
|
static void* pipe_do_setup(int num, void* arg) {
|
136
|
-
pipe_conn_rec* conns;
|
137
136
|
pipe_conn_rec* pe;
|
138
137
|
pipe_conn_rec* p;
|
139
138
|
int r;
|
140
139
|
|
141
|
-
|
142
|
-
closed_streams = 0;
|
143
|
-
|
144
|
-
conns = calloc(num, sizeof(pipe_conn_rec));
|
145
|
-
ASSERT(conns != NULL);
|
146
|
-
|
147
|
-
for (p = conns, pe = p + num; p < pe; p++) {
|
140
|
+
for (p = pipe_conns, pe = p + num; p < pe; p++) {
|
148
141
|
r = uv_pipe_init(&p->stream);
|
149
142
|
ASSERT(r == 0);
|
150
|
-
p->stream.data = p;
|
151
|
-
p->conn_req.data = p;
|
152
|
-
p->write_req.data = p;
|
153
|
-
p->conn_req.handle = (uv_stream_t*)&p->stream;
|
154
|
-
p->write_req.handle = (uv_stream_t*)&p->stream;
|
155
143
|
}
|
156
144
|
|
157
|
-
return
|
145
|
+
return pipe_conns;
|
158
146
|
}
|
159
147
|
|
160
148
|
|
@@ -165,9 +153,11 @@ static int tcp_do_connect(int num, void* conns, void* arg) {
|
|
165
153
|
int r;
|
166
154
|
|
167
155
|
addr = uv_ip4_addr("127.0.0.1", TEST_PORT);
|
168
|
-
for (p =
|
156
|
+
for (p = tcp_conns, pe = p + num; p < pe; p++) {
|
169
157
|
r = uv_tcp_connect(&p->conn_req, &p->stream, addr, connect_cb);
|
170
158
|
ASSERT(r == 0);
|
159
|
+
|
160
|
+
p->conn_req.data = p;
|
171
161
|
}
|
172
162
|
|
173
163
|
return 0;
|
@@ -179,9 +169,11 @@ static int pipe_do_connect(int num, void* conns, void* arg) {
|
|
179
169
|
pipe_conn_rec* p;
|
180
170
|
int r;
|
181
171
|
|
182
|
-
for (p =
|
172
|
+
for (p = pipe_conns, pe = p + num; p < pe; p++) {
|
183
173
|
r = uv_pipe_connect(&p->conn_req, &p->stream, TEST_PIPENAME, connect_cb);
|
184
174
|
ASSERT(r == 0);
|
175
|
+
|
176
|
+
p->conn_req.data = p;
|
185
177
|
}
|
186
178
|
|
187
179
|
return 0;
|
@@ -193,25 +185,35 @@ static int pound_it(int concurrency,
|
|
193
185
|
setup_fn do_setup,
|
194
186
|
connect_fn do_connect,
|
195
187
|
void* arg) {
|
188
|
+
double secs;
|
196
189
|
void* state;
|
197
190
|
int r;
|
198
191
|
|
199
192
|
uv_init();
|
200
193
|
|
201
|
-
|
202
|
-
|
194
|
+
/* Run benchmark for at least five seconds. */
|
195
|
+
start_time = uv_hrtime();
|
196
|
+
do {
|
197
|
+
state = do_setup(concurrency, arg);
|
198
|
+
ASSERT(state != NULL);
|
203
199
|
|
204
|
-
|
205
|
-
|
200
|
+
r = do_connect(concurrency, state, arg);
|
201
|
+
ASSERT(!r);
|
206
202
|
|
207
|
-
|
208
|
-
ASSERT(!r);
|
203
|
+
uv_run();
|
209
204
|
|
210
|
-
|
205
|
+
end_time = uv_hrtime();
|
206
|
+
}
|
207
|
+
while ((end_time - start_time) < 5 * NANOSEC);
|
211
208
|
|
212
|
-
|
213
|
-
|
214
|
-
|
209
|
+
/* Number of fractional seconds it took to run the benchmark. */
|
210
|
+
secs = (double)(end_time - start_time) / NANOSEC;
|
211
|
+
|
212
|
+
LOGF("%s-conn-pound-%d: %.0f accepts/s (%d failed)\n",
|
213
|
+
type,
|
214
|
+
concurrency,
|
215
|
+
closed_streams / secs,
|
216
|
+
conns_failed);
|
215
217
|
|
216
218
|
return 0;
|
217
219
|
}
|
@@ -234,4 +236,4 @@ BENCHMARK_IMPL(pipe_pound_100) {
|
|
234
236
|
|
235
237
|
BENCHMARK_IMPL(pipe_pound_1000) {
|
236
238
|
return pound_it(1000, "pipe", pipe_do_setup, pipe_do_connect, NULL);
|
237
|
-
}
|
239
|
+
}
|
@@ -90,7 +90,7 @@ static void after_read(uv_stream_t* handle, ssize_t nread, uv_buf_t buf) {
|
|
90
90
|
return;
|
91
91
|
}
|
92
92
|
|
93
|
-
/*
|
93
|
+
/*
|
94
94
|
* Scan for the letter Q which signals that we should quit the server.
|
95
95
|
* If we get QS it means close the stream.
|
96
96
|
*/
|
@@ -99,7 +99,7 @@ static void after_read(uv_stream_t* handle, ssize_t nread, uv_buf_t buf) {
|
|
99
99
|
if (buf.base[i] == 'Q') {
|
100
100
|
if (i + 1 < nread && buf.base[i + 1] == 'S') {
|
101
101
|
free(buf.base);
|
102
|
-
uv_close((uv_handle_t*)handle,
|
102
|
+
uv_close((uv_handle_t*)handle, on_close);
|
103
103
|
return;
|
104
104
|
} else {
|
105
105
|
uv_close(server, on_server_close);
|
@@ -70,6 +70,7 @@ TEST_DECLARE (spawn_and_kill)
|
|
70
70
|
#ifdef _WIN32
|
71
71
|
TEST_DECLARE (spawn_detect_pipe_name_collisions_on_windows)
|
72
72
|
TEST_DECLARE (argument_escaping)
|
73
|
+
TEST_DECLARE (environment_creation)
|
73
74
|
#endif
|
74
75
|
HELPER_DECLARE (tcp4_echo_server)
|
75
76
|
HELPER_DECLARE (tcp6_echo_server)
|
@@ -155,6 +156,7 @@ TASK_LIST_START
|
|
155
156
|
#ifdef _WIN32
|
156
157
|
TEST_ENTRY (spawn_detect_pipe_name_collisions_on_windows)
|
157
158
|
TEST_ENTRY (argument_escaping)
|
159
|
+
TEST_ENTRY (environment_creation)
|
158
160
|
#endif
|
159
161
|
|
160
162
|
#if 0
|
@@ -340,6 +340,53 @@ TEST_IMPL(argument_escaping) {
|
|
340
340
|
ASSERT(wcscmp(verbatim_output, L"cmd.exe /c c:\\path\\to\\node.exe --eval \"require('c:\\\\path\\\\to\\\\test.js')\"") == 0);
|
341
341
|
ASSERT(wcscmp(non_verbatim_output, L"cmd.exe /c \"c:\\path\\to\\node.exe --eval \\\"require('c:\\\\path\\\\to\\\\test.js')\\\"\"") == 0);
|
342
342
|
|
343
|
+
free(verbatim_output);
|
344
|
+
free(non_verbatim_output);
|
345
|
+
|
343
346
|
return 0;
|
344
347
|
}
|
345
|
-
|
348
|
+
|
349
|
+
wchar_t* make_program_env(char** env_block);
|
350
|
+
|
351
|
+
TEST_IMPL(environment_creation) {
|
352
|
+
int i;
|
353
|
+
char* environment[] = {
|
354
|
+
"FOO=BAR",
|
355
|
+
"SYSTEM=ROOT", /* substring of a supplied var name */
|
356
|
+
"SYSTEMROOTED=OMG", /* supplied var name is a substring */
|
357
|
+
"TEMP=C:\\Temp",
|
358
|
+
"BAZ=QUX",
|
359
|
+
NULL
|
360
|
+
};
|
361
|
+
|
362
|
+
wchar_t expected[512];
|
363
|
+
wchar_t* ptr = expected;
|
364
|
+
wchar_t* result;
|
365
|
+
wchar_t* str;
|
366
|
+
|
367
|
+
for (i = 0; i < sizeof(environment) / sizeof(environment[0]) - 1; i++) {
|
368
|
+
ptr += uv_utf8_to_utf16(environment[i], ptr, expected + sizeof(expected) - ptr);
|
369
|
+
}
|
370
|
+
|
371
|
+
memcpy(ptr, L"SYSTEMROOT=", sizeof(L"SYSTEMROOT="));
|
372
|
+
ptr += sizeof(L"SYSTEMROOT=")/sizeof(wchar_t) - 1;
|
373
|
+
ptr += GetEnvironmentVariableW(L"SYSTEMROOT", ptr, expected + sizeof(expected) - ptr);
|
374
|
+
++ptr;
|
375
|
+
|
376
|
+
memcpy(ptr, L"SYSTEMDRIVE=", sizeof(L"SYSTEMDRIVE="));
|
377
|
+
ptr += sizeof(L"SYSTEMDRIVE=")/sizeof(wchar_t) - 1;
|
378
|
+
ptr += GetEnvironmentVariableW(L"SYSTEMDRIVE", ptr, expected + sizeof(expected) - ptr);
|
379
|
+
++ptr;
|
380
|
+
*ptr = '\0';
|
381
|
+
|
382
|
+
result = make_program_env(environment);
|
383
|
+
|
384
|
+
for (str = result; *str; str += wcslen(str) + 1) {
|
385
|
+
wprintf(L"%s\n", str);
|
386
|
+
}
|
387
|
+
|
388
|
+
ASSERT(wcscmp(expected, result) == 0);
|
389
|
+
|
390
|
+
return 0;
|
391
|
+
}
|
392
|
+
#endif
|