noderb 0.0.3 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|