noderb 0.0.8 → 0.0.9

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 (84) hide show
  1. data/ext/noderb_extension/extconf.rb +4 -2
  2. data/ext/noderb_extension/libuv/AUTHORS +2 -0
  3. data/ext/noderb_extension/libuv/Makefile +1 -1
  4. data/ext/noderb_extension/libuv/common.gypi +51 -51
  5. data/ext/noderb_extension/libuv/config-mingw.mk +3 -9
  6. data/ext/noderb_extension/libuv/config-unix.mk +10 -1
  7. data/ext/noderb_extension/libuv/include/uv-private/uv-unix.h +3 -2
  8. data/ext/noderb_extension/libuv/include/uv-private/uv-win.h +7 -6
  9. data/ext/noderb_extension/libuv/include/uv.h +47 -13
  10. data/ext/noderb_extension/libuv/src/ares/config_netbsd/ares_config.h +510 -0
  11. data/ext/noderb_extension/libuv/src/unix/core.c +20 -65
  12. data/ext/noderb_extension/libuv/src/unix/darwin.c +1 -0
  13. data/ext/noderb_extension/libuv/src/unix/eio/config_netbsd.h +81 -0
  14. data/ext/noderb_extension/libuv/src/unix/error.c +9 -1
  15. data/ext/noderb_extension/libuv/src/unix/ev/config_netbsd.h +120 -0
  16. data/ext/noderb_extension/libuv/src/unix/fs.c +151 -21
  17. data/ext/noderb_extension/libuv/src/unix/internal.h +30 -0
  18. data/ext/noderb_extension/libuv/src/unix/netbsd.c +68 -0
  19. data/ext/noderb_extension/libuv/src/unix/pipe.c +20 -30
  20. data/ext/noderb_extension/libuv/src/unix/process.c +13 -0
  21. data/ext/noderb_extension/libuv/src/unix/stream.c +105 -63
  22. data/ext/noderb_extension/libuv/src/unix/tcp.c +75 -21
  23. data/ext/noderb_extension/libuv/src/unix/tty.c +69 -0
  24. data/ext/noderb_extension/libuv/src/unix/udp.c +31 -0
  25. data/ext/noderb_extension/libuv/src/uv-common.c +2 -0
  26. data/ext/noderb_extension/libuv/src/uv-common.h +0 -6
  27. data/ext/noderb_extension/libuv/src/win/cares.c +7 -7
  28. data/ext/noderb_extension/libuv/src/win/core.c +25 -17
  29. data/ext/noderb_extension/libuv/src/win/error.c +7 -0
  30. data/ext/noderb_extension/libuv/src/win/fs.c +587 -92
  31. data/ext/noderb_extension/libuv/src/win/getaddrinfo.c +3 -1
  32. data/ext/noderb_extension/libuv/src/win/handle.c +0 -17
  33. data/ext/noderb_extension/libuv/src/win/internal.h +15 -5
  34. data/ext/noderb_extension/libuv/src/win/loop-watcher.c +1 -1
  35. data/ext/noderb_extension/libuv/src/win/pipe.c +6 -0
  36. data/ext/noderb_extension/libuv/src/win/process.c +90 -43
  37. data/ext/noderb_extension/libuv/src/win/tcp.c +37 -4
  38. data/ext/noderb_extension/libuv/src/win/threads.c +81 -0
  39. data/ext/noderb_extension/libuv/src/win/timer.c +15 -15
  40. data/ext/noderb_extension/libuv/src/win/tty.c +37 -0
  41. data/ext/noderb_extension/libuv/src/win/udp.c +8 -2
  42. data/ext/noderb_extension/libuv/src/win/winapi.c +12 -0
  43. data/ext/noderb_extension/libuv/src/win/winapi.h +1146 -1015
  44. data/ext/noderb_extension/libuv/test/benchmark-ares.c +0 -1
  45. data/ext/noderb_extension/libuv/test/benchmark-getaddrinfo.c +0 -1
  46. data/ext/noderb_extension/libuv/test/benchmark-ping-pongs.c +0 -1
  47. data/ext/noderb_extension/libuv/test/benchmark-pound.c +0 -1
  48. data/ext/noderb_extension/libuv/test/benchmark-pump.c +4 -6
  49. data/ext/noderb_extension/libuv/test/benchmark-spawn.c +0 -1
  50. data/ext/noderb_extension/libuv/test/benchmark-udp-packet-storm.c +0 -1
  51. data/ext/noderb_extension/libuv/test/dns-server.c +2 -2
  52. data/ext/noderb_extension/libuv/test/echo-server.c +4 -5
  53. data/ext/noderb_extension/libuv/test/run-tests.c +0 -2
  54. data/ext/noderb_extension/libuv/test/test-async.c +0 -2
  55. data/ext/noderb_extension/libuv/test/test-callback-stack.c +0 -2
  56. data/ext/noderb_extension/libuv/test/test-connection-fail.c +3 -5
  57. data/ext/noderb_extension/libuv/test/test-delayed-accept.c +2 -3
  58. data/ext/noderb_extension/libuv/test/test-fs.c +578 -42
  59. data/ext/noderb_extension/libuv/test/test-get-currentexe.c +12 -2
  60. data/ext/noderb_extension/libuv/test/test-getaddrinfo.c +10 -5
  61. data/ext/noderb_extension/libuv/test/test-gethostbyname.c +0 -2
  62. data/ext/noderb_extension/libuv/test/test-getsockname.c +92 -72
  63. data/ext/noderb_extension/libuv/test/test-idle.c +0 -3
  64. data/ext/noderb_extension/libuv/test/test-list.h +13 -0
  65. data/ext/noderb_extension/libuv/test/test-loop-handles.c +0 -3
  66. data/ext/noderb_extension/libuv/test/test-ping-pong.c +13 -19
  67. data/ext/noderb_extension/libuv/test/test-pipe-bind-error.c +0 -12
  68. data/ext/noderb_extension/libuv/test/test-ref.c +0 -7
  69. data/ext/noderb_extension/libuv/test/test-shutdown-eof.c +3 -3
  70. data/ext/noderb_extension/libuv/test/test-spawn.c +2 -11
  71. data/ext/noderb_extension/libuv/test/test-tcp-bind-error.c +0 -19
  72. data/ext/noderb_extension/libuv/test/test-tcp-bind6-error.c +0 -15
  73. data/ext/noderb_extension/libuv/test/test-tcp-close.c +129 -0
  74. data/ext/noderb_extension/libuv/test/test-tcp-writealot.c +0 -3
  75. data/ext/noderb_extension/libuv/test/test-threadpool.c +0 -2
  76. data/ext/noderb_extension/libuv/test/test-timer-again.c +0 -3
  77. data/ext/noderb_extension/libuv/test/test-timer.c +0 -2
  78. data/ext/noderb_extension/libuv/test/test-udp-dgram-too-big.c +0 -2
  79. data/ext/noderb_extension/libuv/test/test-udp-ipv6.c +0 -2
  80. data/ext/noderb_extension/libuv/test/test-udp-send-and-recv.c +0 -2
  81. data/ext/noderb_extension/libuv/uv.gyp +18 -2
  82. data/ext/noderb_extension/noderb_fs.c +1 -2
  83. data/lib/noderb/version.rb +1 -1
  84. metadata +10 -2
@@ -29,7 +29,7 @@
29
29
  /*
30
30
  * MinGW is missing this
31
31
  */
32
- #ifndef _MSC_VER
32
+ #if !defined(_MSC_VER) && !defined(__MINGW64_VERSION_MAJOR)
33
33
  typedef struct addrinfoW {
34
34
  int ai_flags;
35
35
  int ai_family;
@@ -255,6 +255,8 @@ int uv_getaddrinfo(uv_loop_t* loop,
255
255
  goto error;
256
256
  }
257
257
 
258
+ uv_req_init(loop, (uv_req_t*)handle);
259
+
258
260
  handle->getaddrinfo_cb = getaddrinfo_cb;
259
261
  handle->res = NULL;
260
262
  handle->type = UV_GETADDRINFO;
@@ -39,23 +39,6 @@ int uv_is_active(uv_handle_t* handle) {
39
39
  }
40
40
 
41
41
 
42
- int uv_getsockname(uv_handle_t* handle, struct sockaddr* name, int* namelen) {
43
- uv_loop_t* loop = handle->loop;
44
-
45
- switch (handle->type) {
46
- case UV_TCP:
47
- return uv_tcp_getsockname(loop, (uv_tcp_t*) handle, name, namelen);
48
-
49
- case UV_UDP:
50
- return uv_udp_getsockname(loop, (uv_udp_t*) handle, name, namelen);
51
-
52
- default:
53
- uv_set_sys_error(loop, WSAENOTSOCK);
54
- return -1;
55
- }
56
- }
57
-
58
-
59
42
  void uv_close(uv_handle_t* handle, uv_close_cb cb) {
60
43
  uv_tcp_t* tcp;
61
44
  uv_pipe_t* pipe;
@@ -123,8 +123,6 @@ int uv_tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb,
123
123
  uv_read_cb read_cb);
124
124
  int uv_tcp_write(uv_loop_t* loop, uv_write_t* req, uv_tcp_t* handle,
125
125
  uv_buf_t bufs[], int bufcnt, uv_write_cb cb);
126
- int uv_tcp_getsockname(uv_loop_t* loop, uv_tcp_t* handle,
127
- struct sockaddr* name, int* namelen);
128
126
 
129
127
  void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, uv_req_t* req);
130
128
  void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle,
@@ -140,9 +138,6 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle);
140
138
  /*
141
139
  * UDP
142
140
  */
143
- int uv_udp_getsockname(uv_loop_t* loop, uv_udp_t* handle,
144
- struct sockaddr* name, int* namelen);
145
-
146
141
  void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle, uv_req_t* req);
147
142
  void uv_process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle,
148
143
  uv_udp_send_t* req);
@@ -284,4 +279,19 @@ void uv_winsock_init();
284
279
  int uv_ntstatus_to_winsock_error(NTSTATUS status);
285
280
 
286
281
 
282
+ /* Threads and synchronization */
283
+ typedef struct uv_once_s {
284
+ unsigned char ran;
285
+ /* The actual event handle must be aligned to sizeof(HANDLE), so in */
286
+ /* practice it might overlap padding a little. */
287
+ HANDLE event;
288
+ HANDLE padding;
289
+ } uv_once_t;
290
+
291
+ #define UV_ONCE_INIT \
292
+ { 0, NULL, NULL }
293
+
294
+ void uv_once(uv_once_t* guard, void (*callback)(void));
295
+
296
+
287
297
  #endif /* UV_WIN_INTERNAL_H_ */
@@ -49,7 +49,7 @@ void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle) {
49
49
  uv_ref(loop); \
50
50
  \
51
51
  loop->counters.handle_init++; \
52
- loop->counters.##name##_init++; \
52
+ loop->counters.name##_init++; \
53
53
  \
54
54
  return 0; \
55
55
  } \
@@ -1059,3 +1059,9 @@ static void eof_timer_close_cb(uv_handle_t* handle) {
1059
1059
  assert(handle->type == UV_TIMER);
1060
1060
  free(handle);
1061
1061
  }
1062
+
1063
+
1064
+ void uv_pipe_open(uv_pipe_t* pipe, uv_file file) {
1065
+ assert(0 && "implement me");
1066
+ }
1067
+
@@ -61,12 +61,9 @@ static void uv_process_init(uv_loop_t* loop, uv_process_t* handle) {
61
61
  handle->wait_handle = INVALID_HANDLE_VALUE;
62
62
  handle->process_handle = INVALID_HANDLE_VALUE;
63
63
  handle->close_handle = INVALID_HANDLE_VALUE;
64
- handle->stdio_pipes[0].server_pipe = NULL;
65
- handle->stdio_pipes[0].child_pipe = INVALID_HANDLE_VALUE;
66
- handle->stdio_pipes[1].server_pipe = NULL;
67
- handle->stdio_pipes[1].child_pipe = INVALID_HANDLE_VALUE;
68
- handle->stdio_pipes[2].server_pipe = NULL;
69
- handle->stdio_pipes[2].child_pipe = INVALID_HANDLE_VALUE;
64
+ handle->child_stdio[0] = INVALID_HANDLE_VALUE;
65
+ handle->child_stdio[1] = INVALID_HANDLE_VALUE;
66
+ handle->child_stdio[2] = INVALID_HANDLE_VALUE;
70
67
 
71
68
  uv_req_init(loop, (uv_req_t*)&handle->exit_req);
72
69
  handle->exit_req.type = UV_PROCESS_EXIT;
@@ -625,7 +622,7 @@ static DWORD WINAPI spawn_failure(void* data) {
625
622
  char unknown[] = "unknown error\n";
626
623
  uv_process_t* process = (uv_process_t*) data;
627
624
  uv_loop_t* loop = process->loop;
628
- HANDLE child_stderr = process->stdio_pipes[2].child_pipe;
625
+ HANDLE child_stderr = process->child_stdio[2];
629
626
  char* buf = NULL;
630
627
  DWORD count, written;
631
628
 
@@ -657,18 +654,23 @@ static DWORD WINAPI spawn_failure(void* data) {
657
654
  }
658
655
 
659
656
 
660
- /* Called on main thread after a child process has exited. */
661
- void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle) {
657
+ static void close_child_stdio(uv_process_t* process) {
662
658
  int i;
663
- DWORD exit_code;
659
+ HANDLE handle;
664
660
 
665
- /* Close stdio handles. */
666
- for (i = 0; i < COUNTOF(handle->stdio_pipes); i++) {
667
- if (handle->stdio_pipes[i].child_pipe != INVALID_HANDLE_VALUE) {
668
- CloseHandle(handle->stdio_pipes[i].child_pipe);
669
- handle->stdio_pipes[i].child_pipe = INVALID_HANDLE_VALUE;
661
+ for (i = 0; i < COUNTOF(process->child_stdio); i++) {
662
+ handle = process->child_stdio[i];
663
+ if (handle != NULL && handle != INVALID_HANDLE_VALUE) {
664
+ CloseHandle(handle);
665
+ process->child_stdio[i] = INVALID_HANDLE_VALUE;
670
666
  }
671
667
  }
668
+ }
669
+
670
+
671
+ /* Called on main thread after a child process has exited. */
672
+ void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle) {
673
+ DWORD exit_code;
672
674
 
673
675
  /* Unregister from process notification. */
674
676
  if (handle->wait_handle != INVALID_HANDLE_VALUE) {
@@ -686,6 +688,10 @@ void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle) {
686
688
  CloseHandle(handle->process_handle);
687
689
  handle->process_handle = INVALID_HANDLE_VALUE;
688
690
  } else {
691
+ /* We probably left the child stdio handles open to report the error */
692
+ /* asynchronously, so close them now. */
693
+ close_child_stdio(handle);
694
+
689
695
  /* The process never even started in the first place. */
690
696
  exit_code = 127;
691
697
  }
@@ -805,13 +811,45 @@ done:
805
811
  }
806
812
 
807
813
 
814
+ static int duplicate_std_handle(uv_loop_t* loop, DWORD id, HANDLE* dup) {
815
+ HANDLE handle;
816
+ HANDLE current_process = GetCurrentProcess();
817
+
818
+ handle = GetStdHandle(id);
819
+
820
+ if (handle == NULL) {
821
+ *dup = NULL;
822
+ return 0;
823
+ } else if (handle == INVALID_HANDLE_VALUE) {
824
+ *dup = INVALID_HANDLE_VALUE;
825
+ uv_set_sys_error(loop, GetLastError());
826
+ return -1;
827
+ }
828
+
829
+ if (!DuplicateHandle(current_process,
830
+ handle,
831
+ current_process,
832
+ dup,
833
+ 0,
834
+ TRUE,
835
+ DUPLICATE_SAME_ACCESS)) {
836
+ *dup = INVALID_HANDLE_VALUE;
837
+ uv_set_sys_error(loop, GetLastError());
838
+ return -1;
839
+ }
840
+
841
+ return 0;
842
+ }
843
+
844
+
808
845
  int uv_spawn(uv_loop_t* loop, uv_process_t* process,
809
846
  uv_process_options_t options) {
810
- int err = 0, i;
847
+ int err = 0, keep_child_stdio_open = 0;
811
848
  wchar_t* path;
812
849
  int size;
813
850
  BOOL result;
814
851
  wchar_t* application_path, *application, *arguments, *env, *cwd;
852
+ HANDLE* child_stdio = process->child_stdio;
815
853
  STARTUPINFOW startup;
816
854
  PROCESS_INFORMATION info;
817
855
 
@@ -864,41 +902,41 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process,
864
902
  err = uv_create_stdio_pipe_pair(
865
903
  loop,
866
904
  options.stdin_stream,
867
- &process->stdio_pipes[0].child_pipe,
905
+ &child_stdio[0],
868
906
  PIPE_ACCESS_OUTBOUND,
869
907
  GENERIC_READ | FILE_WRITE_ATTRIBUTES);
870
- if (err) {
871
- goto done;
872
- }
873
-
874
- process->stdio_pipes[0].server_pipe = options.stdin_stream;
908
+ } else {
909
+ err = duplicate_std_handle(loop, STD_INPUT_HANDLE, &child_stdio[0]);
910
+ }
911
+ if (err) {
912
+ goto done;
875
913
  }
876
914
 
877
915
  if (options.stdout_stream) {
878
916
  err = uv_create_stdio_pipe_pair(
879
917
  loop, options.stdout_stream,
880
- &process->stdio_pipes[1].child_pipe,
918
+ &child_stdio[1],
881
919
  PIPE_ACCESS_INBOUND,
882
920
  GENERIC_WRITE);
883
- if (err) {
884
- goto done;
885
- }
886
-
887
- process->stdio_pipes[1].server_pipe = options.stdout_stream;
921
+ } else {
922
+ err = duplicate_std_handle(loop, STD_OUTPUT_HANDLE, &child_stdio[1]);
923
+ }
924
+ if (err) {
925
+ goto done;
888
926
  }
889
927
 
890
928
  if (options.stderr_stream) {
891
929
  err = uv_create_stdio_pipe_pair(
892
930
  loop,
893
931
  options.stderr_stream,
894
- &process->stdio_pipes[2].child_pipe,
932
+ &child_stdio[2],
895
933
  PIPE_ACCESS_INBOUND,
896
934
  GENERIC_WRITE);
897
- if (err) {
898
- goto done;
899
- }
900
-
901
- process->stdio_pipes[2].server_pipe = options.stderr_stream;
935
+ } else {
936
+ err = duplicate_std_handle(loop, STD_ERROR_HANDLE, &child_stdio[2]);
937
+ }
938
+ if (err) {
939
+ goto done;
902
940
  }
903
941
 
904
942
  startup.cb = sizeof(startup);
@@ -908,9 +946,9 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process,
908
946
  startup.dwFlags = STARTF_USESTDHANDLES;
909
947
  startup.cbReserved2 = 0;
910
948
  startup.lpReserved2 = NULL;
911
- startup.hStdInput = process->stdio_pipes[0].child_pipe;
912
- startup.hStdOutput = process->stdio_pipes[1].child_pipe;
913
- startup.hStdError = process->stdio_pipes[2].child_pipe;
949
+ startup.hStdInput = child_stdio[0];
950
+ startup.hStdOutput = child_stdio[1];
951
+ startup.hStdError = child_stdio[2];
914
952
 
915
953
  if (CreateProcessW(application_path,
916
954
  arguments,
@@ -942,6 +980,7 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process,
942
980
  /* succeeded, and start a thread instead that prints an error */
943
981
  /* to the child's intended stderr. */
944
982
  process->spawn_errno = GetLastError();
983
+ keep_child_stdio_open = 1;
945
984
  if (!QueueUserWorkItem(spawn_failure, process, WT_EXECUTEDEFAULT)) {
946
985
  uv_fatal_error(GetLastError(), "QueueUserWorkItem");
947
986
  }
@@ -957,14 +996,22 @@ done:
957
996
  free(env);
958
997
  free(path);
959
998
 
960
- if (err) {
961
- for (i = 0; i < COUNTOF(process->stdio_pipes); i++) {
962
- if (process->stdio_pipes[i].child_pipe != INVALID_HANDLE_VALUE) {
963
- CloseHandle(process->stdio_pipes[i].child_pipe);
964
- process->stdio_pipes[i].child_pipe = INVALID_HANDLE_VALUE;
965
- }
999
+ /* Under normal circumstances we should close the stdio handles now - */
1000
+ /* the child now has its own duplicates, or something went horribly wrong. */
1001
+ /* The only exception is when CreateProcess has failed, then we actually */
1002
+ /* need to keep the stdio handles to report the error asynchronously. */
1003
+ if (!keep_child_stdio_open) {
1004
+ close_child_stdio(process);
1005
+ } else {
1006
+ /* We're keeping the handles open, the thread pool is going to have */
1007
+ /* it's way with them. But at least make them noninheritable. */
1008
+ int i;
1009
+ for (i = 0; i < COUNTOF(process->child_stdio); i++) {
1010
+ SetHandleInformation(child_stdio[i], HANDLE_FLAG_INHERIT, 0);
966
1011
  }
1012
+ }
967
1013
 
1014
+ if (err) {
968
1015
  if (process->wait_handle != INVALID_HANDLE_VALUE) {
969
1016
  UnregisterWait(process->wait_handle);
970
1017
  process->wait_handle = INVALID_HANDLE_VALUE;
@@ -419,6 +419,8 @@ int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client) {
419
419
  rv = -1;
420
420
  } else {
421
421
  uv_connection_init((uv_stream_t*) client);
422
+ /* AcceptEx() implicitly binds the accepted socket. */
423
+ client->flags |= UV_HANDLE_BOUND;
422
424
  }
423
425
 
424
426
  /* Prepare the req to pick up a new connection */
@@ -573,12 +575,18 @@ int uv_tcp_connect6(uv_connect_t* req, uv_tcp_t* handle,
573
575
  }
574
576
 
575
577
 
576
- int uv_tcp_getsockname(uv_loop_t* loop, uv_tcp_t* handle,
577
- struct sockaddr* name, int* namelen) {
578
+ int uv_tcp_getsockname(uv_tcp_t* handle, struct sockaddr* name,
579
+ int* namelen) {
580
+ uv_loop_t* loop = handle->loop;
578
581
  int result;
579
582
 
580
- if (handle->flags & UV_HANDLE_SHUTTING) {
581
- uv_set_sys_error(loop, WSAESHUTDOWN);
583
+ if (!(handle->flags & UV_HANDLE_BOUND)) {
584
+ uv_set_sys_error(loop, WSAEINVAL);
585
+ return -1;
586
+ }
587
+
588
+ if (handle->flags & UV_HANDLE_BIND_ERROR) {
589
+ loop->last_error = handle->bind_error;
582
590
  return -1;
583
591
  }
584
592
 
@@ -592,6 +600,31 @@ int uv_tcp_getsockname(uv_loop_t* loop, uv_tcp_t* handle,
592
600
  }
593
601
 
594
602
 
603
+ int uv_tcp_getpeername(uv_tcp_t* handle, struct sockaddr* name,
604
+ int* namelen) {
605
+ uv_loop_t* loop = handle->loop;
606
+ int result;
607
+
608
+ if (!(handle->flags & UV_HANDLE_BOUND)) {
609
+ uv_set_sys_error(loop, WSAEINVAL);
610
+ return -1;
611
+ }
612
+
613
+ if (handle->flags & UV_HANDLE_BIND_ERROR) {
614
+ loop->last_error = handle->bind_error;
615
+ return -1;
616
+ }
617
+
618
+ result = getpeername(handle->socket, name, namelen);
619
+ if (result != 0) {
620
+ uv_set_sys_error(loop, WSAGetLastError());
621
+ return -1;
622
+ }
623
+
624
+ return 0;
625
+ }
626
+
627
+
595
628
  int uv_tcp_write(uv_loop_t* loop, uv_write_t* req, uv_tcp_t* handle,
596
629
  uv_buf_t bufs[], int bufcnt, uv_write_cb cb) {
597
630
  int result;
@@ -0,0 +1,81 @@
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
+ #ifdef _MSC_VER /* msvc */
30
+ # define NOINLINE __declspec (noinline)
31
+ #else /* gcc */
32
+ # define NOINLINE __attribute__ ((noinline))
33
+ #endif
34
+
35
+
36
+ static NOINLINE void uv__once_inner(uv_once_t* guard,
37
+ void (*callback)(void)) {
38
+ DWORD result;
39
+ HANDLE existing_event, created_event;
40
+ HANDLE* event_ptr;
41
+
42
+ /* Fetch and align event_ptr */
43
+ event_ptr = (HANDLE*) (((uintptr_t) &guard->event + (sizeof(HANDLE) - 1)) &
44
+ ~(sizeof(HANDLE) - 1));
45
+
46
+ created_event = CreateEvent(NULL, 1, 0, NULL);
47
+ if (created_event == 0) {
48
+ /* Could fail in a low-memory situation? */
49
+ uv_fatal_error(GetLastError(), "CreateEvent");
50
+ }
51
+
52
+ existing_event = InterlockedCompareExchangePointer(event_ptr,
53
+ created_event,
54
+ NULL);
55
+
56
+ if (existing_event == NULL) {
57
+ /* We won the race */
58
+ callback();
59
+
60
+ result = SetEvent(created_event);
61
+ assert(result);
62
+ guard->ran = 1;
63
+
64
+ } else {
65
+ /* We lost the race. Destroy the event we created and wait for the */
66
+ /* existing one to become signaled. */
67
+ CloseHandle(created_event);
68
+ result = WaitForSingleObject(existing_event, INFINITE);
69
+ assert(result == WAIT_OBJECT_0);
70
+ }
71
+ }
72
+
73
+
74
+ void uv_once(uv_once_t* guard, void (*callback)(void)) {
75
+ /* Fast case - avoid WaitForSingleObject. */
76
+ if (guard->ran) {
77
+ return;
78
+ }
79
+
80
+ uv__once_inner(guard, callback);
81
+ }