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.
Files changed (51) hide show
  1. data/README.md +157 -7
  2. data/ext/noderb_extension/extconf.rb +1 -3
  3. data/ext/noderb_extension/libuv/BSDmakefile +2 -0
  4. data/ext/noderb_extension/libuv/all.gyp +326 -0
  5. data/ext/noderb_extension/libuv/config-mingw.mk +0 -1
  6. data/ext/noderb_extension/libuv/config-unix.mk +7 -1
  7. data/ext/noderb_extension/libuv/create-msvs-files.bat +13 -6
  8. data/ext/noderb_extension/libuv/{build/gyp_uv → gyp_uv} +1 -2
  9. data/ext/noderb_extension/libuv/include/uv.h +5 -0
  10. data/ext/noderb_extension/libuv/src/eio/config_cygwin.h +3 -0
  11. data/ext/noderb_extension/libuv/src/eio/config_freebsd.h +3 -0
  12. data/ext/noderb_extension/libuv/src/eio/config_sunos.h +3 -0
  13. data/ext/noderb_extension/libuv/src/eio/ecb.h +1 -1
  14. data/ext/noderb_extension/libuv/src/eio/eio.c +8 -1
  15. data/ext/noderb_extension/libuv/src/uv-common.c +1 -0
  16. data/ext/noderb_extension/libuv/src/uv-sunos.c +1 -1
  17. data/ext/noderb_extension/libuv/src/uv-unix.c +72 -59
  18. data/ext/noderb_extension/libuv/src/win/core.c +3 -0
  19. data/ext/noderb_extension/libuv/src/win/internal.h +11 -0
  20. data/ext/noderb_extension/libuv/src/win/ntdll.h +130 -0
  21. data/ext/noderb_extension/libuv/src/win/pipe.c +105 -27
  22. data/ext/noderb_extension/libuv/src/win/process.c +76 -5
  23. data/ext/noderb_extension/libuv/src/win/req.c +7 -0
  24. data/ext/noderb_extension/libuv/src/win/winapi.c +52 -0
  25. data/ext/noderb_extension/libuv/test/benchmark-pound.c +50 -48
  26. data/ext/noderb_extension/libuv/test/echo-server.c +2 -2
  27. data/ext/noderb_extension/libuv/test/test-list.h +2 -0
  28. data/ext/noderb_extension/libuv/test/test-spawn.c +48 -1
  29. data/ext/noderb_extension/noderb.c +38 -339
  30. data/ext/noderb_extension/noderb.h +18 -2
  31. data/ext/noderb_extension/noderb_common.h +13 -0
  32. data/ext/noderb_extension/noderb_dns.c +37 -0
  33. data/ext/noderb_extension/noderb_dns.h +15 -0
  34. data/ext/noderb_extension/noderb_process.c +126 -0
  35. data/ext/noderb_extension/noderb_process.h +17 -0
  36. data/ext/noderb_extension/noderb_tcp.c +127 -0
  37. data/ext/noderb_extension/noderb_tcp.h +19 -0
  38. data/ext/noderb_extension/noderb_timers.c +58 -0
  39. data/ext/noderb_extension/noderb_timers.h +16 -0
  40. data/ext/noderb_extension/noderb_tools.c +127 -0
  41. data/ext/noderb_extension/noderb_tools.h +33 -0
  42. data/lib/noderb/dns.rb +11 -0
  43. data/lib/noderb/next_tick.rb +2 -1
  44. data/lib/noderb/tcp.rb +27 -0
  45. data/lib/noderb/timers.rb +24 -0
  46. data/lib/noderb/version.rb +1 -1
  47. data/lib/noderb.rb +6 -1
  48. metadata +23 -7
  49. data/ext/noderb_extension/libuv/build/all.gyp +0 -254
  50. data/ext/noderb_extension/libuv/doc/desired-api.md +0 -159
  51. /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
- close_pipe(handle, &status, &err);
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 (handle->shutdown_req->cb) {
158
- if (status == -1) {
159
- LOOP->last_error = err;
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
- handle->shutdown_req->cb(handle->shutdown_req, status);
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
- /* TODO: do we need to check avail > 0? */
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
- if (bytes > 0) {
732
- /* Successful read */
733
- handle->read_cb((uv_stream_t*)handle, bytes, buf);
734
- /* Read again only if bytes == buf.len */
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
- * The way windows takes environment variables is different than what C does;
499
- * Windows wants a contiguous block of null-terminated strings, terminated
500
- * with an additional null.
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
- dst = (wchar_t*)malloc(env_len);
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 int64_t start_time, end_time;
49
- static int closed_streams, concurrency;
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
- concurrency = num;
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 conns;
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
- concurrency = num;
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 conns;
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 = conns, pe = p + num; p < pe; 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 = conns, pe = p + num; p < pe; 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
- state = do_setup(concurrency, arg);
202
- ASSERT(state != NULL);
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
- uv_update_time();
205
- start_time = uv_now();
200
+ r = do_connect(concurrency, state, arg);
201
+ ASSERT(!r);
206
202
 
207
- r = do_connect(concurrency, state, arg);
208
- ASSERT(!r);
203
+ uv_run();
209
204
 
210
- uv_run();
205
+ end_time = uv_hrtime();
206
+ }
207
+ while ((end_time - start_time) < 5 * NANOSEC);
211
208
 
212
- LOGF("%s-conn-pound-%d: %.0f accepts/s\n",
213
- type, concurrency,
214
- (double) concurrency / (double) (end_time - start_time) * 1000.0);
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, NULL);
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
- #endif
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