noderb 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
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